wicked-crew 0.5.0 → 0.7.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/api/audit.d.ts +70 -0
- package/dist/api/audit.d.ts.map +1 -0
- package/dist/api/audit.js +131 -0
- package/dist/api/audit.js.map +1 -0
- package/dist/api/auth.d.ts +192 -0
- package/dist/api/auth.d.ts.map +1 -0
- package/dist/api/auth.js +515 -0
- package/dist/api/auth.js.map +1 -0
- package/dist/api/gate-cache.d.ts +8 -0
- package/dist/api/gate-cache.d.ts.map +1 -1
- package/dist/api/gate-cache.js +10 -0
- package/dist/api/gate-cache.js.map +1 -1
- package/dist/api/guidance-index.d.ts +39 -0
- package/dist/api/guidance-index.d.ts.map +1 -0
- package/dist/api/guidance-index.js +67 -0
- package/dist/api/guidance-index.js.map +1 -0
- package/dist/api/open-path.d.ts +34 -0
- package/dist/api/open-path.d.ts.map +1 -0
- package/dist/api/open-path.js +101 -0
- package/dist/api/open-path.js.map +1 -0
- package/dist/api/retry-index.d.ts +30 -0
- package/dist/api/retry-index.d.ts.map +1 -0
- package/dist/api/retry-index.js +45 -0
- package/dist/api/retry-index.js.map +1 -0
- package/dist/api/routes.d.ts +164 -1
- package/dist/api/routes.d.ts.map +1 -1
- package/dist/api/routes.js +769 -21
- package/dist/api/routes.js.map +1 -1
- package/dist/api/run-files.d.ts +63 -0
- package/dist/api/run-files.d.ts.map +1 -0
- package/dist/api/run-files.js +271 -0
- package/dist/api/run-files.js.map +1 -0
- package/dist/api/seat-health.d.ts +55 -0
- package/dist/api/seat-health.d.ts.map +1 -0
- package/dist/api/seat-health.js +273 -0
- package/dist/api/seat-health.js.map +1 -0
- package/dist/api/seat-signin.d.ts +27 -0
- package/dist/api/seat-signin.d.ts.map +1 -0
- package/dist/api/seat-signin.js +143 -0
- package/dist/api/seat-signin.js.map +1 -0
- package/dist/api/server.d.ts +190 -3
- package/dist/api/server.d.ts.map +1 -1
- package/dist/api/server.js +365 -11
- package/dist/api/server.js.map +1 -1
- package/dist/api/stall-watchdog.d.ts +62 -0
- package/dist/api/stall-watchdog.d.ts.map +1 -0
- package/dist/api/stall-watchdog.js +138 -0
- package/dist/api/stall-watchdog.js.map +1 -0
- package/dist/cli/index.js +171 -12
- package/dist/cli/index.js.map +1 -1
- package/dist/cli/mcp.d.ts +14 -0
- package/dist/cli/mcp.d.ts.map +1 -0
- package/dist/cli/mcp.js +119 -0
- package/dist/cli/mcp.js.map +1 -0
- package/dist/core/adapter.d.ts +87 -10
- package/dist/core/adapter.d.ts.map +1 -1
- package/dist/core/adapter.js +347 -28
- package/dist/core/adapter.js.map +1 -1
- package/dist/core/bridge-reaper.d.ts +134 -0
- package/dist/core/bridge-reaper.d.ts.map +1 -0
- package/dist/core/bridge-reaper.js +286 -0
- package/dist/core/bridge-reaper.js.map +1 -0
- package/dist/core/deliver.d.ts +118 -0
- package/dist/core/deliver.d.ts.map +1 -0
- package/dist/core/deliver.js +241 -0
- package/dist/core/deliver.js.map +1 -0
- package/dist/core/deliverable-floor.d.ts +103 -0
- package/dist/core/deliverable-floor.d.ts.map +1 -0
- package/dist/core/deliverable-floor.js +173 -0
- package/dist/core/deliverable-floor.js.map +1 -0
- package/dist/core/exec.d.ts +2 -0
- package/dist/core/exec.d.ts.map +1 -1
- package/dist/core/exec.js.map +1 -1
- package/dist/core/types.d.ts +92 -352
- package/dist/core/types.d.ts.map +1 -1
- package/dist/core/types.js +14 -4
- package/dist/core/types.js.map +1 -1
- package/dist/interactive/bridge-pool.d.ts +99 -0
- package/dist/interactive/bridge-pool.d.ts.map +1 -0
- package/dist/interactive/bridge-pool.js +244 -0
- package/dist/interactive/bridge-pool.js.map +1 -0
- package/dist/interactive/bridge-root.d.ts +36 -0
- package/dist/interactive/bridge-root.d.ts.map +1 -0
- package/dist/interactive/bridge-root.js +48 -0
- package/dist/interactive/bridge-root.js.map +1 -0
- package/dist/interactive/chat-events.d.ts +207 -0
- package/dist/interactive/chat-events.d.ts.map +1 -0
- package/dist/interactive/chat-events.js +769 -0
- package/dist/interactive/chat-events.js.map +1 -0
- package/dist/interactive/demo-events.d.ts +283 -0
- package/dist/interactive/demo-events.d.ts.map +1 -0
- package/dist/interactive/demo-events.js +889 -0
- package/dist/interactive/demo-events.js.map +1 -0
- package/dist/interactive/draft-events.d.ts +224 -0
- package/dist/interactive/draft-events.d.ts.map +1 -0
- package/dist/interactive/draft-events.js +793 -0
- package/dist/interactive/draft-events.js.map +1 -0
- package/dist/interactive/edit-events.d.ts +194 -0
- package/dist/interactive/edit-events.d.ts.map +1 -0
- package/dist/interactive/edit-events.js +601 -0
- package/dist/interactive/edit-events.js.map +1 -0
- package/dist/interactive/ledger.d.ts +39 -0
- package/dist/interactive/ledger.d.ts.map +1 -0
- package/dist/interactive/ledger.js +93 -0
- package/dist/interactive/ledger.js.map +1 -0
- package/dist/interactive/proxy-routes.d.ts +39 -0
- package/dist/interactive/proxy-routes.d.ts.map +1 -0
- package/dist/interactive/proxy-routes.js +189 -0
- package/dist/interactive/proxy-routes.js.map +1 -0
- package/dist/interactive/repo-snapshot.d.ts +100 -0
- package/dist/interactive/repo-snapshot.d.ts.map +1 -0
- package/dist/interactive/repo-snapshot.js +289 -0
- package/dist/interactive/repo-snapshot.js.map +1 -0
- package/dist/interactive/ws-relay.d.ts +85 -0
- package/dist/interactive/ws-relay.d.ts.map +1 -0
- package/dist/interactive/ws-relay.js +191 -0
- package/dist/interactive/ws-relay.js.map +1 -0
- package/dist/projects/activity.d.ts +29 -0
- package/dist/projects/activity.d.ts.map +1 -0
- package/dist/projects/activity.js +172 -0
- package/dist/projects/activity.js.map +1 -0
- package/dist/projects/charter.d.ts +28 -0
- package/dist/projects/charter.d.ts.map +1 -0
- package/dist/projects/charter.js +53 -0
- package/dist/projects/charter.js.map +1 -0
- package/dist/projects/events.d.ts +55 -0
- package/dist/projects/events.d.ts.map +1 -0
- package/dist/projects/events.js +141 -0
- package/dist/projects/events.js.map +1 -0
- package/dist/projects/graph-paths.d.ts +92 -0
- package/dist/projects/graph-paths.d.ts.map +1 -0
- package/dist/projects/graph-paths.js +130 -0
- package/dist/projects/graph-paths.js.map +1 -0
- package/dist/projects/graph.d.ts +179 -0
- package/dist/projects/graph.d.ts.map +1 -0
- package/dist/projects/graph.js +775 -0
- package/dist/projects/graph.js.map +1 -0
- package/dist/projects/membership-index.d.ts +25 -0
- package/dist/projects/membership-index.d.ts.map +1 -0
- package/dist/projects/membership-index.js +46 -0
- package/dist/projects/membership-index.js.map +1 -0
- package/dist/projects/routes.d.ts +97 -0
- package/dist/projects/routes.d.ts.map +1 -0
- package/dist/projects/routes.js +510 -0
- package/dist/projects/routes.js.map +1 -0
- package/dist/projects/settings.d.ts +32 -0
- package/dist/projects/settings.d.ts.map +1 -0
- package/dist/projects/settings.js +64 -0
- package/dist/projects/settings.js.map +1 -0
- package/dist/qe/acceptance.d.ts +137 -0
- package/dist/qe/acceptance.d.ts.map +1 -0
- package/dist/qe/acceptance.js +249 -0
- package/dist/qe/acceptance.js.map +1 -0
- package/dist/qe/gate-events.d.ts +111 -0
- package/dist/qe/gate-events.d.ts.map +1 -0
- package/dist/qe/gate-events.js +168 -0
- package/dist/qe/gate-events.js.map +1 -0
- package/dist/qe/ledger.d.ts +100 -0
- package/dist/qe/ledger.d.ts.map +1 -0
- package/dist/qe/ledger.js +154 -0
- package/dist/qe/ledger.js.map +1 -0
- package/dist/studio/assets/index-8p8uwCxG.js +530 -0
- package/dist/studio/assets/index-D6S9zUtO.css +32 -0
- package/dist/studio/index.html +5 -3
- package/package.json +10 -4
- package/dist/studio/assets/index-DaaUU8Ep.css +0 -32
- package/dist/studio/assets/index-Fu5DRC00.js +0 -423
package/dist/api/auth.js
ADDED
|
@@ -0,0 +1,515 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The daemon's identity/actor seam (task #88, locked decision #6).
|
|
3
|
+
*
|
|
4
|
+
* LOCAL IS SACRED: the default deployment stays exactly what it was — a
|
|
5
|
+
* 127.0.0.1-bound daemon with loopback CORS and NO auth, where every request
|
|
6
|
+
* implicitly acts as the full-trust local operator. Nothing in this module
|
|
7
|
+
* runs a verifier, reads a token file, or changes a response in that mode; it
|
|
8
|
+
* only pins ONE actor shape onto the request so downstream code (audit trail,
|
|
9
|
+
* bus events, gate decisions) never branches on "was there auth".
|
|
10
|
+
*
|
|
11
|
+
* TEAM/HOSTED REQUIRES AUTH: `WICKED_RUNTIME=team` or `WICKED_CREW_AUTH=required`
|
|
12
|
+
* arms a bearer-token check on `/api/v1/*` and the `/ws` upgrade paths.
|
|
13
|
+
* Verification is pluggable behind {@link TokenVerifier}; v1 ships the static
|
|
14
|
+
* workload-token verifier (hashed-at-rest file, {@link loadTokenFile}) and the
|
|
15
|
+
* OIDC verifier SEAM ({@link OidcConfig} + {@link createOidcVerifier}), whose
|
|
16
|
+
* implementation is a named follow-up — configuring OIDC today fails the boot
|
|
17
|
+
* LOUDLY rather than pretending an IdP was consulted.
|
|
18
|
+
*
|
|
19
|
+
* Deny semantics: missing/unknown token in required mode → 401 (with
|
|
20
|
+
* `WWW-Authenticate: Bearer`); an authenticated actor below a route's rung on
|
|
21
|
+
* the trust ladder → 403. The ladder is {@link requiredTrust} — minimal and
|
|
22
|
+
* documented (docs/auth.md), not a per-route registry.
|
|
23
|
+
*/
|
|
24
|
+
import { readFileSync, statSync } from 'node:fs';
|
|
25
|
+
import { homedir } from 'node:os';
|
|
26
|
+
import { join } from 'node:path';
|
|
27
|
+
import { constants, createHash, createPublicKey, verify as cryptoVerify } from 'node:crypto';
|
|
28
|
+
import { API_PREFIX } from './api-prefix.js';
|
|
29
|
+
/**
|
|
30
|
+
* The implicit full-trust local operator. `admin` is the ladder's top rung —
|
|
31
|
+
* the local single-operator deployment has exactly one human and no boundary
|
|
32
|
+
* to enforce between that human and the daemon, so "full trust" and "admin"
|
|
33
|
+
* are the same fact spelled once.
|
|
34
|
+
*/
|
|
35
|
+
export const LOCAL_ACTOR = Object.freeze({
|
|
36
|
+
id: 'local',
|
|
37
|
+
kind: 'human',
|
|
38
|
+
trust: 'admin',
|
|
39
|
+
});
|
|
40
|
+
const TRUST_RANK = { observer: 0, operator: 1, admin: 2 };
|
|
41
|
+
const KINDS = new Set(['human', 'agent', 'system']);
|
|
42
|
+
const TRUSTS = new Set(['observer', 'operator', 'admin']);
|
|
43
|
+
/** True when `actor` sits at or above `min` on the ladder. */
|
|
44
|
+
export function trustAtLeast(actor, min) {
|
|
45
|
+
return TRUST_RANK[actor.trust] >= TRUST_RANK[min];
|
|
46
|
+
}
|
|
47
|
+
/**
|
|
48
|
+
* Resolve the daemon's auth mode. DENY-DOMINANT: `WICKED_RUNTIME=team` forces
|
|
49
|
+
* `required` and nothing can talk it back down — a team runtime with auth
|
|
50
|
+
* switched off is exactly the silently-ungoverned state this seam exists to
|
|
51
|
+
* prevent. Outside team runtime, `WICKED_CREW_AUTH` (`required`|`off`) is
|
|
52
|
+
* explicit; unset means the local default, off.
|
|
53
|
+
*/
|
|
54
|
+
export function resolveAuthMode(env = process.env) {
|
|
55
|
+
if (env['WICKED_RUNTIME']?.trim().toLowerCase() === 'team')
|
|
56
|
+
return 'required';
|
|
57
|
+
const explicit = env['WICKED_CREW_AUTH']?.trim().toLowerCase();
|
|
58
|
+
if (explicit === undefined || explicit === '' || explicit === 'off')
|
|
59
|
+
return 'off';
|
|
60
|
+
if (explicit === 'required')
|
|
61
|
+
return 'required';
|
|
62
|
+
// An unknown value fails LOUD rather than defaulting to off: a typo'd
|
|
63
|
+
// `WICKED_CREW_AUTH=reqired` silently running unauthenticated is the worst
|
|
64
|
+
// possible reading of an operator's stated intent to authenticate.
|
|
65
|
+
throw new Error(`WICKED_CREW_AUTH must be 'required' or 'off' (got '${explicit}')`);
|
|
66
|
+
}
|
|
67
|
+
/** Where the workload-token file lives unless overridden. */
|
|
68
|
+
export function defaultTokensPath(env = process.env) {
|
|
69
|
+
return env['WICKED_CREW_TOKENS'] ?? join(homedir(), '.config', 'wicked-crew', 'tokens.json');
|
|
70
|
+
}
|
|
71
|
+
/** `sha256` hex of a presented token — the only form the daemon stores or compares. */
|
|
72
|
+
export function tokenHash(token) {
|
|
73
|
+
return createHash('sha256').update(token, 'utf8').digest('hex');
|
|
74
|
+
}
|
|
75
|
+
const SHA256_HEX = /^[0-9a-f]{64}$/;
|
|
76
|
+
/**
|
|
77
|
+
* Parse a tokens.json payload into a hash→actor map. FAILS CLOSED on any
|
|
78
|
+
* malformed entry: a typo'd trust level that silently skipped its entry would
|
|
79
|
+
* lock an operator out (or, worse, a hand-edit that half-parsed would demote
|
|
80
|
+
* someone) with nothing saying so. The error names the entry index and field.
|
|
81
|
+
*/
|
|
82
|
+
export function parseTokenFile(json, source) {
|
|
83
|
+
let raw;
|
|
84
|
+
try {
|
|
85
|
+
raw = JSON.parse(json);
|
|
86
|
+
}
|
|
87
|
+
catch (err) {
|
|
88
|
+
throw new Error(`${source}: not valid JSON (${err instanceof Error ? err.message : String(err)})`);
|
|
89
|
+
}
|
|
90
|
+
const file = raw;
|
|
91
|
+
if (typeof file !== 'object' || file === null || !Array.isArray(file.tokens)) {
|
|
92
|
+
throw new Error(`${source}: expected { "version": 1, "tokens": [...] }`);
|
|
93
|
+
}
|
|
94
|
+
if (file.version !== undefined && file.version !== 1) {
|
|
95
|
+
throw new Error(`${source}: unsupported version ${JSON.stringify(file.version)} (this build reads version 1)`);
|
|
96
|
+
}
|
|
97
|
+
const map = new Map();
|
|
98
|
+
file.tokens.forEach((entry, i) => {
|
|
99
|
+
const e = entry;
|
|
100
|
+
const at = `${source}: tokens[${i}]`;
|
|
101
|
+
if (typeof e?.sha256 !== 'string' || !SHA256_HEX.test(e.sha256)) {
|
|
102
|
+
throw new Error(`${at}: 'sha256' must be 64 lowercase hex chars (sha256 of the token)`);
|
|
103
|
+
}
|
|
104
|
+
const a = e.actor;
|
|
105
|
+
if (typeof a?.id !== 'string' || a.id.length === 0 || a.id.length > 128) {
|
|
106
|
+
throw new Error(`${at}: 'actor.id' must be a non-empty string (≤128 chars)`);
|
|
107
|
+
}
|
|
108
|
+
if (typeof a.kind !== 'string' || !KINDS.has(a.kind)) {
|
|
109
|
+
throw new Error(`${at}: 'actor.kind' must be 'human' | 'agent' | 'system'`);
|
|
110
|
+
}
|
|
111
|
+
if (typeof a.trust !== 'string' || !TRUSTS.has(a.trust)) {
|
|
112
|
+
throw new Error(`${at}: 'actor.trust' must be 'observer' | 'operator' | 'admin'`);
|
|
113
|
+
}
|
|
114
|
+
if (map.has(e.sha256)) {
|
|
115
|
+
throw new Error(`${at}: duplicate token hash (also used by an earlier entry)`);
|
|
116
|
+
}
|
|
117
|
+
map.set(e.sha256, Object.freeze({ id: a.id, kind: a.kind, trust: a.trust }));
|
|
118
|
+
});
|
|
119
|
+
return map;
|
|
120
|
+
}
|
|
121
|
+
/**
|
|
122
|
+
* Load `tokens.json` from disk into a static verifier. A MISSING file is a
|
|
123
|
+
* loud warning, not a boot failure: the daemon still starts and every request
|
|
124
|
+
* 401s, which is the honest fail-closed posture (an unreachable daemon tells
|
|
125
|
+
* the operator less than one that answers "no tokens are registered").
|
|
126
|
+
* A PRESENT-but-malformed file fails the boot — see {@link parseTokenFile}.
|
|
127
|
+
*/
|
|
128
|
+
export function loadTokenFile(path, warn) {
|
|
129
|
+
let json;
|
|
130
|
+
try {
|
|
131
|
+
json = readFileSync(path, 'utf8');
|
|
132
|
+
}
|
|
133
|
+
catch (err) {
|
|
134
|
+
if (err.code === 'ENOENT') {
|
|
135
|
+
warn(`[auth] required mode with NO token file at ${path} — every /api/v1 and /ws request will 401 ` +
|
|
136
|
+
`until tokens are registered (docs/auth.md § "Workload tokens")`);
|
|
137
|
+
return new Map();
|
|
138
|
+
}
|
|
139
|
+
throw new Error(`[auth] cannot read token file ${path}: ${err instanceof Error ? err.message : String(err)}`);
|
|
140
|
+
}
|
|
141
|
+
// Hashes, not tokens, live in this file — but its actor/trust mappings are
|
|
142
|
+
// still authorization state, so a group/world-writable file is worth a shout.
|
|
143
|
+
if (process.platform !== 'win32') {
|
|
144
|
+
try {
|
|
145
|
+
const mode = statSync(path).mode & 0o077;
|
|
146
|
+
if (mode !== 0) {
|
|
147
|
+
warn(`[auth] ${path} is group/world-accessible (mode ${(statSync(path).mode & 0o777).toString(8)}) — chmod 600 recommended`);
|
|
148
|
+
}
|
|
149
|
+
}
|
|
150
|
+
catch {
|
|
151
|
+
/* stat raced a delete; the read above already succeeded */
|
|
152
|
+
}
|
|
153
|
+
}
|
|
154
|
+
return parseTokenFile(json, path);
|
|
155
|
+
}
|
|
156
|
+
/** The static workload-token verifier: sha256 the presented token, look it up. */
|
|
157
|
+
export function createStaticVerifier(entries) {
|
|
158
|
+
return {
|
|
159
|
+
name: 'static-tokens',
|
|
160
|
+
verify: (token) => Promise.resolve(entries.get(tokenHash(token)) ?? null),
|
|
161
|
+
};
|
|
162
|
+
}
|
|
163
|
+
/** Where the auth config (OIDC seam) lives unless overridden. */
|
|
164
|
+
export function defaultAuthConfigPath(env = process.env) {
|
|
165
|
+
return env['WICKED_CREW_AUTH_CONFIG'] ?? join(homedir(), '.config', 'wicked-crew', 'auth.json');
|
|
166
|
+
}
|
|
167
|
+
/** Per-issuer JWKS cache: keys indexed by kid (or by alg when kid is absent). */
|
|
168
|
+
const JWKS_CACHE = new Map();
|
|
169
|
+
const JWKS_TTL_MS = 5 * 60 * 1000; // 5-min TTL; synchronous re-fetch on stale or unknown kid
|
|
170
|
+
function base64urlDecode(s) {
|
|
171
|
+
const pad = (4 - (s.length % 4)) % 4;
|
|
172
|
+
return Buffer.from(s.replace(/-/g, '+').replace(/_/g, '/') + '='.repeat(pad), 'base64');
|
|
173
|
+
}
|
|
174
|
+
async function fetchJson(url) {
|
|
175
|
+
const res = await fetch(url, { signal: AbortSignal.timeout(10_000) });
|
|
176
|
+
if (!res.ok)
|
|
177
|
+
throw new Error(`HTTP ${res.status} fetching ${url}`);
|
|
178
|
+
return res.json();
|
|
179
|
+
}
|
|
180
|
+
async function fetchJwks(jwksUri) {
|
|
181
|
+
const doc = await fetchJson(jwksUri);
|
|
182
|
+
const map = new Map();
|
|
183
|
+
for (const key of doc.keys ?? []) {
|
|
184
|
+
if (key.use !== undefined && key.use !== 'sig')
|
|
185
|
+
continue;
|
|
186
|
+
// Index by kid; fall back to alg when kid is absent.
|
|
187
|
+
const index = key.kid ?? key.alg ?? key.kty;
|
|
188
|
+
map.set(index, key);
|
|
189
|
+
}
|
|
190
|
+
return map;
|
|
191
|
+
}
|
|
192
|
+
async function resolveJwksUri(config) {
|
|
193
|
+
if (config.jwksUri)
|
|
194
|
+
return config.jwksUri;
|
|
195
|
+
const discovery = await fetchJson(`${config.issuer.replace(/\/$/, '')}/.well-known/openid-configuration`);
|
|
196
|
+
return discovery.jwks_uri;
|
|
197
|
+
}
|
|
198
|
+
async function getJwk(config, kid, allowRefresh) {
|
|
199
|
+
const cached = JWKS_CACHE.get(config.issuer);
|
|
200
|
+
const stale = !cached || Date.now() - cached.fetchedAt > JWKS_TTL_MS;
|
|
201
|
+
if (cached && !stale) {
|
|
202
|
+
const hit = cached.keys.get(kid);
|
|
203
|
+
if (hit)
|
|
204
|
+
return hit;
|
|
205
|
+
if (!allowRefresh)
|
|
206
|
+
return null;
|
|
207
|
+
}
|
|
208
|
+
// Fetch (or re-fetch on stale/miss).
|
|
209
|
+
const uri = await resolveJwksUri(config);
|
|
210
|
+
const keys = await fetchJwks(uri);
|
|
211
|
+
JWKS_CACHE.set(config.issuer, { keys, fetchedAt: Date.now() });
|
|
212
|
+
return keys.get(kid) ?? null;
|
|
213
|
+
}
|
|
214
|
+
// Supported algorithm → hash algorithm pairs.
|
|
215
|
+
const ALG_HASH = {
|
|
216
|
+
RS256: 'SHA256', RS384: 'SHA384', RS512: 'SHA512',
|
|
217
|
+
ES256: 'SHA256', ES384: 'SHA384', ES512: 'SHA512',
|
|
218
|
+
PS256: 'SHA256', PS384: 'SHA384', PS512: 'SHA512',
|
|
219
|
+
};
|
|
220
|
+
function verifySignature(headerPayload, sig, jwk, alg) {
|
|
221
|
+
const hashAlg = ALG_HASH[alg];
|
|
222
|
+
if (!hashAlg)
|
|
223
|
+
return false;
|
|
224
|
+
try {
|
|
225
|
+
const key = createPublicKey({ key: jwk, format: 'jwk' });
|
|
226
|
+
const opts = alg.startsWith('PS')
|
|
227
|
+
? { padding: constants.RSA_PKCS1_PSS_PADDING, saltLength: constants.RSA_PSS_SALTLEN_DIGEST }
|
|
228
|
+
: alg.startsWith('ES')
|
|
229
|
+
? { dsaEncoding: 'ieee-p1363' }
|
|
230
|
+
: {};
|
|
231
|
+
return cryptoVerify(hashAlg, Buffer.from(headerPayload), { key, ...opts }, sig);
|
|
232
|
+
}
|
|
233
|
+
catch {
|
|
234
|
+
return false;
|
|
235
|
+
}
|
|
236
|
+
}
|
|
237
|
+
/**
|
|
238
|
+
* Verify a raw JWT string against the issuer's JWKS. Returns the decoded
|
|
239
|
+
* payload on success or throws a descriptive error on failure.
|
|
240
|
+
*/
|
|
241
|
+
async function verifyJwt(token, config) {
|
|
242
|
+
const parts = token.split('.');
|
|
243
|
+
if (parts.length !== 3)
|
|
244
|
+
throw new Error('malformed JWT: expected 3 dot-separated parts');
|
|
245
|
+
let header;
|
|
246
|
+
let payload;
|
|
247
|
+
try {
|
|
248
|
+
header = JSON.parse(base64urlDecode(parts[0]).toString('utf8'));
|
|
249
|
+
payload = JSON.parse(base64urlDecode(parts[1]).toString('utf8'));
|
|
250
|
+
}
|
|
251
|
+
catch {
|
|
252
|
+
throw new Error('malformed JWT: header or payload is not valid base64url JSON');
|
|
253
|
+
}
|
|
254
|
+
const alg = header.alg ?? '';
|
|
255
|
+
if (!ALG_HASH[alg])
|
|
256
|
+
throw new Error(`unsupported JWT algorithm: ${alg}`);
|
|
257
|
+
const kid = header.kid ?? alg;
|
|
258
|
+
const sig = base64urlDecode(parts[2]);
|
|
259
|
+
const headerPayload = `${parts[0]}.${parts[1]}`;
|
|
260
|
+
// Try cached key first; re-fetch once on unknown kid.
|
|
261
|
+
const jwk = await getJwk(config, kid, true);
|
|
262
|
+
if (!jwk)
|
|
263
|
+
throw new Error(`no JWKS key found for kid=${JSON.stringify(kid)}`);
|
|
264
|
+
if (!verifySignature(headerPayload, sig, jwk, alg)) {
|
|
265
|
+
throw new Error('JWT signature verification failed');
|
|
266
|
+
}
|
|
267
|
+
// Claim validation.
|
|
268
|
+
const now = Math.floor(Date.now() / 1000);
|
|
269
|
+
if (typeof payload.iss !== 'string' || payload.iss !== config.issuer) {
|
|
270
|
+
throw new Error(`JWT issuer mismatch: expected ${config.issuer}, got ${JSON.stringify(payload.iss)}`);
|
|
271
|
+
}
|
|
272
|
+
const audList = Array.isArray(payload.aud) ? payload.aud : [payload.aud];
|
|
273
|
+
if (!audList.includes(config.audience)) {
|
|
274
|
+
throw new Error(`JWT audience mismatch: expected ${config.audience}, got ${JSON.stringify(payload.aud)}`);
|
|
275
|
+
}
|
|
276
|
+
if (typeof payload.exp !== 'number') {
|
|
277
|
+
throw new Error('JWT is missing required exp claim');
|
|
278
|
+
}
|
|
279
|
+
if (payload.exp <= now) {
|
|
280
|
+
throw new Error('JWT has expired (exp)');
|
|
281
|
+
}
|
|
282
|
+
if (typeof payload.nbf === 'number' && payload.nbf > now) {
|
|
283
|
+
throw new Error('JWT is not yet valid (nbf)');
|
|
284
|
+
}
|
|
285
|
+
return payload;
|
|
286
|
+
}
|
|
287
|
+
function mapOidcActor(payload, config) {
|
|
288
|
+
const idClaim = config.claims?.id ?? 'sub';
|
|
289
|
+
const rawId = payload[idClaim];
|
|
290
|
+
const id = typeof rawId === 'string' && rawId.length > 0 ? rawId : payload.sub ?? '';
|
|
291
|
+
if (!id)
|
|
292
|
+
throw new Error(`JWT has no value for id claim '${idClaim}' or 'sub'`);
|
|
293
|
+
const trustClaim = config.claims?.trust;
|
|
294
|
+
const rawTrust = trustClaim ? payload[trustClaim] : undefined;
|
|
295
|
+
const defaultTrust = config.defaultTrust ?? 'observer';
|
|
296
|
+
const rawTrustStr = String(rawTrust);
|
|
297
|
+
const trust = TRUSTS.has(rawTrustStr) ? rawTrustStr : defaultTrust;
|
|
298
|
+
return Object.freeze({ id, kind: 'human', trust });
|
|
299
|
+
}
|
|
300
|
+
/**
|
|
301
|
+
* Create an OIDC verifier that validates JWTs against the issuer's JWKS.
|
|
302
|
+
* Supports RS256/384/512, ES256/384/512, PS256/384/512. JWKS keys are cached
|
|
303
|
+
* per issuer with a 5-minute TTL and auto-refreshed on unknown kid.
|
|
304
|
+
*/
|
|
305
|
+
export function createOidcVerifier(config) {
|
|
306
|
+
// Validate config at creation time — a misconfigured issuer URL is caught
|
|
307
|
+
// immediately at boot rather than silently during the first verification.
|
|
308
|
+
if (!config.issuer || !config.issuer.startsWith('https://')) {
|
|
309
|
+
throw new Error(`[auth] OIDC config: 'issuer' must be an https:// URL (got ${JSON.stringify(config.issuer)})`);
|
|
310
|
+
}
|
|
311
|
+
if (config.defaultTrust !== undefined && !TRUSTS.has(config.defaultTrust)) {
|
|
312
|
+
throw new Error(`[auth] OIDC config: 'defaultTrust' must be observer|operator|admin (got ${JSON.stringify(config.defaultTrust)})`);
|
|
313
|
+
}
|
|
314
|
+
if (!config.audience) {
|
|
315
|
+
throw new Error(`[auth] OIDC config: 'audience' is required`);
|
|
316
|
+
}
|
|
317
|
+
return {
|
|
318
|
+
name: 'oidc',
|
|
319
|
+
async verify(token) {
|
|
320
|
+
// A JWT has exactly 3 base64url segments separated by dots. Static
|
|
321
|
+
// workload tokens are opaque strings and won't have this shape — the
|
|
322
|
+
// verifier chain tries static-tokens first, so if we get called the
|
|
323
|
+
// token isn't a known workload token. But don't assume it's a JWT either.
|
|
324
|
+
if (!token.includes('.'))
|
|
325
|
+
return null; // clearly not a JWT; pass through
|
|
326
|
+
try {
|
|
327
|
+
const payload = await verifyJwt(token, config);
|
|
328
|
+
return mapOidcActor(payload, config);
|
|
329
|
+
}
|
|
330
|
+
catch {
|
|
331
|
+
// Any verification failure → null so the chain can try the next
|
|
332
|
+
// verifier (or 401 if none match). The deny-401 path logs the failure.
|
|
333
|
+
return null;
|
|
334
|
+
}
|
|
335
|
+
},
|
|
336
|
+
};
|
|
337
|
+
}
|
|
338
|
+
/** Resolve mode + verifier chain. Reads files ONLY in required mode. */
|
|
339
|
+
export function resolveAuth(options, warn) {
|
|
340
|
+
const mode = options?.mode ?? resolveAuthMode();
|
|
341
|
+
const originsEnv = process.env['WICKED_CREW_ALLOWED_ORIGINS'];
|
|
342
|
+
const allowedOrigins = options?.allowedOrigins ??
|
|
343
|
+
(originsEnv !== undefined && originsEnv.trim() !== ''
|
|
344
|
+
? originsEnv.split(',').map((o) => o.trim()).filter(Boolean)
|
|
345
|
+
: null);
|
|
346
|
+
if (mode === 'off') {
|
|
347
|
+
// Local default: no verifier exists, no file is read, no request is denied.
|
|
348
|
+
return { mode, verifiers: [], allowedOrigins };
|
|
349
|
+
}
|
|
350
|
+
if (options?.verifiers !== undefined) {
|
|
351
|
+
return { mode, verifiers: options.verifiers, allowedOrigins };
|
|
352
|
+
}
|
|
353
|
+
const verifiers = [
|
|
354
|
+
createStaticVerifier(loadTokenFile(options?.tokensPath ?? defaultTokensPath(), warn)),
|
|
355
|
+
];
|
|
356
|
+
// The OIDC seam: configuring it today is a LOUD boot failure, never a silent skip.
|
|
357
|
+
const configPath = options?.configPath ?? defaultAuthConfigPath();
|
|
358
|
+
let configJson = null;
|
|
359
|
+
try {
|
|
360
|
+
configJson = readFileSync(configPath, 'utf8');
|
|
361
|
+
}
|
|
362
|
+
catch (err) {
|
|
363
|
+
// ONLY a missing file is the ordinary case. An unreadable-but-present
|
|
364
|
+
// auth.json (EACCES, EISDIR, …) silently skipping a configured OIDC block
|
|
365
|
+
// would be exactly the quiet misconfiguration this seam refuses to be
|
|
366
|
+
// (Copilot, #250) — so anything else fails the boot, named.
|
|
367
|
+
if (err.code !== 'ENOENT') {
|
|
368
|
+
throw new Error(`[auth] cannot read ${configPath}: ${err instanceof Error ? err.message : String(err)}`);
|
|
369
|
+
}
|
|
370
|
+
configJson = null; // no auth.json — the ordinary case
|
|
371
|
+
}
|
|
372
|
+
if (configJson !== null) {
|
|
373
|
+
let parsed;
|
|
374
|
+
try {
|
|
375
|
+
parsed = JSON.parse(configJson);
|
|
376
|
+
}
|
|
377
|
+
catch (err) {
|
|
378
|
+
throw new Error(`[auth] ${configPath} is not valid JSON: ${err instanceof Error ? err.message : String(err)}`);
|
|
379
|
+
}
|
|
380
|
+
if (parsed.oidc !== undefined) {
|
|
381
|
+
verifiers.push(createOidcVerifier(parsed.oidc)); // throws — the declared seam
|
|
382
|
+
}
|
|
383
|
+
}
|
|
384
|
+
return { mode, verifiers, allowedOrigins };
|
|
385
|
+
}
|
|
386
|
+
// ── The trust ladder over routes ─────────────────────────────────────────────
|
|
387
|
+
/** `PATCH /projects/:id` (exactly one segment after /projects) — see {@link requiredTrust}. */
|
|
388
|
+
const PROJECT_DETAIL_PATH = new RegExp(`^${API_PREFIX}/projects/[^/]+$`);
|
|
389
|
+
/**
|
|
390
|
+
* Minimum trust for a request. Minimal by design (the task's rule: no
|
|
391
|
+
* deny-by-default registry over unknown routes):
|
|
392
|
+
*
|
|
393
|
+
* - `/ws/terminals` and any sub-path → `operator` (write-capable WS channel;
|
|
394
|
+
* inbound frames are raw PTY stdin regardless of the GET upgrade method)
|
|
395
|
+
* - reads (GET/HEAD) and the main `/ws` stream → `observer`
|
|
396
|
+
* - governance writes, settings writes, project archive/restore → `admin`
|
|
397
|
+
* - every other mutation (launch, gate, cancel, chats, terminals, repos,
|
|
398
|
+
* workflows, project CRUD/membership) → `operator`
|
|
399
|
+
*
|
|
400
|
+
* `body` is consulted for exactly one rule: `PATCH /projects/:id` is an
|
|
401
|
+
* `operator` rename/describe unless the patch carries `status` (archive or
|
|
402
|
+
* restore), which changes what the whole team can attach work to — `admin`.
|
|
403
|
+
*/
|
|
404
|
+
export function requiredTrust(method, path, body) {
|
|
405
|
+
// /ws/terminals and any sub-path (e.g. /ws/terminals/:id) are write-capable WS
|
|
406
|
+
// channels — inbound frames are raw PTY stdin. The HTTP upgrade uses GET but the
|
|
407
|
+
// socket carries operator-level writes. Guard both with and without trailing slash.
|
|
408
|
+
if (path === '/ws/terminals' || path.startsWith('/ws/terminals/'))
|
|
409
|
+
return 'operator';
|
|
410
|
+
if (method === 'GET' || method === 'HEAD')
|
|
411
|
+
return 'observer';
|
|
412
|
+
if (path.startsWith(`${API_PREFIX}/governance/`))
|
|
413
|
+
return 'admin';
|
|
414
|
+
if (path === `${API_PREFIX}/settings`)
|
|
415
|
+
return 'admin';
|
|
416
|
+
if (method === 'PATCH' &&
|
|
417
|
+
PROJECT_DETAIL_PATH.test(path) &&
|
|
418
|
+
typeof body === 'object' &&
|
|
419
|
+
body !== null &&
|
|
420
|
+
'status' in body) {
|
|
421
|
+
return 'admin';
|
|
422
|
+
}
|
|
423
|
+
return 'operator';
|
|
424
|
+
}
|
|
425
|
+
/** Path without the query string. */
|
|
426
|
+
function pathOf(req) {
|
|
427
|
+
const url = req.raw.url ?? req.url;
|
|
428
|
+
const q = url.indexOf('?');
|
|
429
|
+
return q >= 0 ? url.slice(0, q) : url;
|
|
430
|
+
}
|
|
431
|
+
/** True for the paths the auth boundary covers: the API and the WS upgrades. */
|
|
432
|
+
export function isProtectedPath(path) {
|
|
433
|
+
return (path === API_PREFIX ||
|
|
434
|
+
path.startsWith(`${API_PREFIX}/`) ||
|
|
435
|
+
path === '/ws' ||
|
|
436
|
+
path.startsWith('/ws/'));
|
|
437
|
+
}
|
|
438
|
+
/**
|
|
439
|
+
* Extract the presented bearer token. `Authorization: Bearer <t>` everywhere;
|
|
440
|
+
* the `/ws` upgrade paths ALSO accept `?access_token=` (RFC 6750 §2.3),
|
|
441
|
+
* because the browser `WebSocket` constructor cannot set headers. Header wins
|
|
442
|
+
* when both are present.
|
|
443
|
+
*/
|
|
444
|
+
export function extractToken(req, path) {
|
|
445
|
+
const header = req.headers.authorization;
|
|
446
|
+
if (typeof header === 'string') {
|
|
447
|
+
const m = /^Bearer\s+(\S+)$/i.exec(header.trim());
|
|
448
|
+
if (m)
|
|
449
|
+
return m[1] ?? null;
|
|
450
|
+
return null; // a malformed Authorization header is not a token
|
|
451
|
+
}
|
|
452
|
+
if (path === '/ws' || path.startsWith('/ws/')) {
|
|
453
|
+
const raw = req.query?.access_token;
|
|
454
|
+
const first = Array.isArray(raw) ? raw[0] : raw;
|
|
455
|
+
if (typeof first === 'string' && first !== '')
|
|
456
|
+
return first;
|
|
457
|
+
}
|
|
458
|
+
return null;
|
|
459
|
+
}
|
|
460
|
+
async function deny401(reply, error) {
|
|
461
|
+
await reply
|
|
462
|
+
.code(401)
|
|
463
|
+
.header('WWW-Authenticate', 'Bearer realm="wicked-crew"')
|
|
464
|
+
.send({ error });
|
|
465
|
+
}
|
|
466
|
+
/**
|
|
467
|
+
* Install the identity (401) and trust (403) hooks.
|
|
468
|
+
*
|
|
469
|
+
* Identity runs at `onRequest` — before body parsing, and (per
|
|
470
|
+
* `@fastify/websocket`) before the upgrade completes, so a bad token is an
|
|
471
|
+
* HTTP 401 on the wire for REST and WS alike. Trust runs at `preHandler`,
|
|
472
|
+
* where the parsed body exists (the one body-dependent rule is the project
|
|
473
|
+
* archive). Both scope to {@link isProtectedPath}; the SPA shell and its
|
|
474
|
+
* assets stay public so a hosted skin can load and ASK for a token.
|
|
475
|
+
*/
|
|
476
|
+
export function registerAuthHooks(app, auth) {
|
|
477
|
+
app.decorateRequest('actor', null);
|
|
478
|
+
app.addHook('onRequest', async (req, reply) => {
|
|
479
|
+
const path = pathOf(req);
|
|
480
|
+
if (!isProtectedPath(path))
|
|
481
|
+
return;
|
|
482
|
+
if (auth.mode === 'off') {
|
|
483
|
+
req.actor = LOCAL_ACTOR;
|
|
484
|
+
return;
|
|
485
|
+
}
|
|
486
|
+
const token = extractToken(req, path);
|
|
487
|
+
if (token === null) {
|
|
488
|
+
return deny401(reply, 'Authentication required: send Authorization: Bearer <token>');
|
|
489
|
+
}
|
|
490
|
+
for (const verifier of auth.verifiers) {
|
|
491
|
+
const actor = await verifier.verify(token);
|
|
492
|
+
if (actor !== null) {
|
|
493
|
+
req.actor = actor;
|
|
494
|
+
return;
|
|
495
|
+
}
|
|
496
|
+
}
|
|
497
|
+
return deny401(reply, 'Invalid or unknown token');
|
|
498
|
+
});
|
|
499
|
+
app.addHook('preHandler', async (req, reply) => {
|
|
500
|
+
const path = pathOf(req);
|
|
501
|
+
if (!isProtectedPath(path))
|
|
502
|
+
return;
|
|
503
|
+
// `actor` is always set here: the onRequest hook either assigned it or
|
|
504
|
+
// already answered 401 (which skips the rest of the lifecycle).
|
|
505
|
+
const need = requiredTrust(req.method, path, req.body);
|
|
506
|
+
if (!trustAtLeast(req.actor, need)) {
|
|
507
|
+
// RETURN the reply — the idiomatic guarantee that the lifecycle stops
|
|
508
|
+
// here and the route handler is never reached (Copilot, #250).
|
|
509
|
+
return reply.code(403).send({
|
|
510
|
+
error: `Insufficient trust: this action requires '${need}' (you are '${req.actor.trust}')`,
|
|
511
|
+
});
|
|
512
|
+
}
|
|
513
|
+
});
|
|
514
|
+
}
|
|
515
|
+
//# sourceMappingURL=auth.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"auth.js","sourceRoot":"","sources":["../../src/api/auth.ts"],"names":[],"mappings":"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"}
|
package/dist/api/gate-cache.d.ts
CHANGED
|
@@ -48,6 +48,14 @@ export declare class GateCache {
|
|
|
48
48
|
rebuild(runId: string, events: CoreEvent[]): GateCacheEntry | undefined;
|
|
49
49
|
/** The cached open gate for a run, if any. */
|
|
50
50
|
get(runId: string): GateCacheEntry | undefined;
|
|
51
|
+
/**
|
|
52
|
+
* Adopt an entry hydrated from the DURABLE `interaction_requests` table (DES-PROJECT-001
|
|
53
|
+
* §5.3). With that table, this cache is finally what its own comments always claimed — a
|
|
54
|
+
* latency layer over durable truth: the route reads the table on a miss and parks the result
|
|
55
|
+
* here so the next poll is a map hit. `rebuild` (event-log replay) remains the fallback for
|
|
56
|
+
* engines predating the table.
|
|
57
|
+
*/
|
|
58
|
+
adopt(runId: string, entry: GateCacheEntry): void;
|
|
51
59
|
/** Drop cache entries whose run is no longer `awaiting_human` (self-healing on reconcile). */
|
|
52
60
|
reconcile(views: SessionView[]): void;
|
|
53
61
|
}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"gate-cache.d.ts","sourceRoot":"","sources":["../../src/api/gate-cache.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,SAAS,EAAE,WAAW,EAAE,MAAM,kBAAkB,CAAC;AAE/D,0CAA0C;AAC1C,MAAM,WAAW,cAAc;IAC7B,4CAA4C;IAC5C,GAAG,EAAE,MAAM,CAAC;IACZ,sFAAsF;IACtF,MAAM,EAAE,MAAM,CAAC;IACf,sFAAsF;IACtF,SAAS,EAAE,MAAM,CAAC;IAClB,yCAAyC;IACzC,UAAU,EAAE,MAAM,CAAC;CACpB;AA+CD;;;;;;;;;;;;;;;;;;GAkBG;AACH,qBAAa,SAAS;IACpB,OAAO,CAAC,QAAQ,CAAC,OAAO,CAAqC;IAE7D,8CAA8C;IAC9C,MAAM,CAAC,KAAK,EAAE,SAAS,GAAG,IAAI;IAI9B;;;;;;;;;;;OAWG;IACH,OAAO,CAAC,KAAK,EAAE,MAAM,EAAE,MAAM,EAAE,SAAS,EAAE,GAAG,cAAc,GAAG,SAAS;IAQvE,8CAA8C;IAC9C,GAAG,CAAC,KAAK,EAAE,MAAM,GAAG,cAAc,GAAG,SAAS;IAI9C,8FAA8F;IAC9F,SAAS,CAAC,KAAK,EAAE,WAAW,EAAE,GAAG,IAAI;CAQtC"}
|
|
1
|
+
{"version":3,"file":"gate-cache.d.ts","sourceRoot":"","sources":["../../src/api/gate-cache.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,SAAS,EAAE,WAAW,EAAE,MAAM,kBAAkB,CAAC;AAE/D,0CAA0C;AAC1C,MAAM,WAAW,cAAc;IAC7B,4CAA4C;IAC5C,GAAG,EAAE,MAAM,CAAC;IACZ,sFAAsF;IACtF,MAAM,EAAE,MAAM,CAAC;IACf,sFAAsF;IACtF,SAAS,EAAE,MAAM,CAAC;IAClB,yCAAyC;IACzC,UAAU,EAAE,MAAM,CAAC;CACpB;AA+CD;;;;;;;;;;;;;;;;;;GAkBG;AACH,qBAAa,SAAS;IACpB,OAAO,CAAC,QAAQ,CAAC,OAAO,CAAqC;IAE7D,8CAA8C;IAC9C,MAAM,CAAC,KAAK,EAAE,SAAS,GAAG,IAAI;IAI9B;;;;;;;;;;;OAWG;IACH,OAAO,CAAC,KAAK,EAAE,MAAM,EAAE,MAAM,EAAE,SAAS,EAAE,GAAG,cAAc,GAAG,SAAS;IAQvE,8CAA8C;IAC9C,GAAG,CAAC,KAAK,EAAE,MAAM,GAAG,cAAc,GAAG,SAAS;IAI9C;;;;;;OAMG;IACH,KAAK,CAAC,KAAK,EAAE,MAAM,EAAE,KAAK,EAAE,cAAc,GAAG,IAAI;IAIjD,8FAA8F;IAC9F,SAAS,CAAC,KAAK,EAAE,WAAW,EAAE,GAAG,IAAI;CAQtC"}
|
package/dist/api/gate-cache.js
CHANGED
|
@@ -92,6 +92,16 @@ export class GateCache {
|
|
|
92
92
|
get(runId) {
|
|
93
93
|
return this.entries.get(runId);
|
|
94
94
|
}
|
|
95
|
+
/**
|
|
96
|
+
* Adopt an entry hydrated from the DURABLE `interaction_requests` table (DES-PROJECT-001
|
|
97
|
+
* §5.3). With that table, this cache is finally what its own comments always claimed — a
|
|
98
|
+
* latency layer over durable truth: the route reads the table on a miss and parks the result
|
|
99
|
+
* here so the next poll is a map hit. `rebuild` (event-log replay) remains the fallback for
|
|
100
|
+
* engines predating the table.
|
|
101
|
+
*/
|
|
102
|
+
adopt(runId, entry) {
|
|
103
|
+
this.entries.set(runId, entry);
|
|
104
|
+
}
|
|
95
105
|
/** Drop cache entries whose run is no longer `awaiting_human` (self-healing on reconcile). */
|
|
96
106
|
reconcile(views) {
|
|
97
107
|
const awaiting = new Set(views.filter((v) => v.session.status === 'awaiting_human').map((v) => v.session.id));
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"gate-cache.js","sourceRoot":"","sources":["../../src/api/gate-cache.ts"],"names":[],"mappings":"AAcA;;;;;;;GAOG;AACH,SAAS,UAAU,CAAC,KAAgB;IAClC,OAAO,IAAI,IAAI,CAAC,OAAO,KAAK,CAAC,EAAE,KAAK,QAAQ,CAAC,CAAC,CAAC,KAAK,CAAC,EAAE,CAAC,CAAC,CAAC,IAAI,CAAC,GAAG,EAAE,CAAC,CAAC,WAAW,EAAE,CAAC;AACtF,CAAC;AAED;;;;;;;GAOG;AACH,SAAS,IAAI,CAAC,OAAoC,EAAE,KAAgB;IAClE,MAAM,OAAO,GAAG,OAAO,KAAK,CAAC,OAAO,KAAK,QAAQ,CAAC,CAAC,CAAC,KAAK,CAAC,OAAO,CAAC,CAAC,CAAC,SAAS,CAAC;IAC9E,IAAI,OAAO,KAAK,SAAS;QAAE,OAAO;IAClC,QAAQ,KAAK,CAAC,IAAI,EAAE,CAAC;QACnB,KAAK,eAAe;YAClB,IAAI,OAAO,KAAK,CAAC,GAAG,KAAK,QAAQ,IAAI,OAAO,KAAK,CAAC,MAAM,KAAK,QAAQ,EAAE,CAAC;gBACtE,OAAO,CAAC,GAAG,CAAC,OAAO,EAAE;oBACnB,GAAG,EAAE,KAAK,CAAC,GAAG;oBACd,MAAM,EAAE,KAAK,CAAC,MAAM;oBACpB,SAAS,EAAE,MAAM;oBACjB,UAAU,EAAE,UAAU,CAAC,KAAK,CAAC;iBAC9B,CAAC,CAAC;YACL,CAAC;YACD,MAAM;QACR,KAAK,SAAS,CAAC;QACf,KAAK,kBAAkB,CAAC;QACxB,KAAK,cAAc,CAAC;QACpB,KAAK,eAAe;YAClB,OAAO,CAAC,MAAM,CAAC,OAAO,CAAC,CAAC;YACxB,MAAM;QACR;YACE,MAAM;IACV,CAAC;AACH,CAAC;AAED;;;;;;;;;;;;;;;;;;GAkBG;AACH,MAAM,OAAO,SAAS;IACH,OAAO,GAAG,IAAI,GAAG,EAA0B,CAAC;IAE7D,8CAA8C;IAC9C,MAAM,CAAC,KAAgB;QACrB,IAAI,CAAC,IAAI,CAAC,OAAO,EAAE,KAAK,CAAC,CAAC;IAC5B,CAAC;IAED;;;;;;;;;;;OAWG;IACH,OAAO,CAAC,KAAa,EAAE,MAAmB;QACxC,MAAM,QAAQ,GAAG,IAAI,GAAG,EAA0B,CAAC;QACnD,KAAK,MAAM,KAAK,IAAI,MAAM;YAAE,IAAI,CAAC,QAAQ,EAAE,KAAK,CAAC,CAAC;QAClD,MAAM,KAAK,GAAG,QAAQ,CAAC,GAAG,CAAC,KAAK,CAAC,CAAC;QAClC,IAAI,KAAK;YAAE,IAAI,CAAC,OAAO,CAAC,GAAG,CAAC,KAAK,EAAE,KAAK,CAAC,CAAC;QAC1C,OAAO,KAAK,CAAC;IACf,CAAC;IAED,8CAA8C;IAC9C,GAAG,CAAC,KAAa;QACf,OAAO,IAAI,CAAC,OAAO,CAAC,GAAG,CAAC,KAAK,CAAC,CAAC;IACjC,CAAC;IAED,8FAA8F;IAC9F,SAAS,CAAC,KAAoB;QAC5B,MAAM,QAAQ,GAAG,IAAI,GAAG,CACtB,KAAK,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,OAAO,CAAC,MAAM,KAAK,gBAAgB,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,OAAO,CAAC,EAAE,CAAC,CACpF,CAAC;QACF,KAAK,MAAM,EAAE,IAAI,CAAC,GAAG,IAAI,CAAC,OAAO,CAAC,IAAI,EAAE,CAAC,EAAE,CAAC;YAC1C,IAAI,CAAC,QAAQ,CAAC,GAAG,CAAC,EAAE,CAAC;gBAAE,IAAI,CAAC,OAAO,CAAC,MAAM,CAAC,EAAE,CAAC,CAAC;QACjD,CAAC;IACH,CAAC;CACF"}
|
|
1
|
+
{"version":3,"file":"gate-cache.js","sourceRoot":"","sources":["../../src/api/gate-cache.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The run→operator-guidance index (DES-UX-002 §7.2, CREW-UX-7).
|
|
3
|
+
*
|
|
4
|
+
* NAMING NOTE: DES-UX-002 §7.2 labels this slice CREW-UX-4, but that id was already spent on an
|
|
5
|
+
* unrelated merged slice (crew#308) — this implementation is CREW-UX-7; the doc's §7.2 spec is
|
|
6
|
+
* what it implements.
|
|
7
|
+
*
|
|
8
|
+
* A durable pre-gate annotation: ONE operator guidance note per run, upserted via
|
|
9
|
+
* `PUT /runs/:id/guidance` and echoed as `AgentSession.guidance` on the run DTOs. The engine's
|
|
10
|
+
* run record carries no such field (wicked-core-ts 0.6.x), so — exactly like retry lineage
|
|
11
|
+
* (CREW-UX-3) and the actor trail (task #88) — the durable record is the audit trail: every
|
|
12
|
+
* write lands as a `guidance.set` entry whose `detail.text` is the full note (empty string =
|
|
13
|
+
* cleared), and this map is the read-side latency layer that lets the run DTOs echo it without
|
|
14
|
+
* a trail scan per request.
|
|
15
|
+
*
|
|
16
|
+
* Mirrors `RetryIndex`'s posture: hydrated once at server start (best-effort — a missing or
|
|
17
|
+
* unreadable trail leaves guidance blank, the pre-CREW-UX-7 behavior, not an error) and updated
|
|
18
|
+
* at the same post-commit point that writes the audit entry, so the map can only lag by a
|
|
19
|
+
* failed hydrate, never diverge silently.
|
|
20
|
+
*/
|
|
21
|
+
import type { AuditLog } from './audit.js';
|
|
22
|
+
export declare class GuidanceIndex {
|
|
23
|
+
private readonly runToGuidance;
|
|
24
|
+
/**
|
|
25
|
+
* Load guidance from EVERY `guidance.set` entry in the trail — exhaustively, not capped
|
|
26
|
+
* (BRIEF-UX-002 C5, same defect as `RetryIndex.hydrate`: a durable note must not vanish
|
|
27
|
+
* because 1000+ newer writes landed on top of it). The trail answers newest first, so the
|
|
28
|
+
* FIRST entry seen per run is the current note — later (older) entries for the same run
|
|
29
|
+
* are superseded writes and are skipped, which is also what keeps a cleared note (newest
|
|
30
|
+
* entry has `text: ''`) from being resurrected by an older non-empty one. Still best-effort,
|
|
31
|
+
* like `RetryIndex.hydrate`; cost is one full-file scan at boot.
|
|
32
|
+
*/
|
|
33
|
+
hydrate(audit: AuditLog, log?: (msg: string) => void): Promise<void>;
|
|
34
|
+
/** Upsert the note; the empty string CLEARS it (the DTO field goes back to absent). */
|
|
35
|
+
set(runId: string, text: string): void;
|
|
36
|
+
/** The note for this run, or `undefined` (the DTO spells that as an ABSENT field). */
|
|
37
|
+
guidanceFor(runId: string): string | undefined;
|
|
38
|
+
}
|
|
39
|
+
//# sourceMappingURL=guidance-index.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"guidance-index.d.ts","sourceRoot":"","sources":["../../src/api/guidance-index.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;GAmBG;AAEH,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,YAAY,CAAC;AAE3C,qBAAa,aAAa;IACxB,OAAO,CAAC,QAAQ,CAAC,aAAa,CAA6B;IAE3D;;;;;;;;OAQG;IACG,OAAO,CAAC,KAAK,EAAE,QAAQ,EAAE,GAAG,CAAC,EAAE,CAAC,GAAG,EAAE,MAAM,KAAK,IAAI,GAAG,OAAO,CAAC,IAAI,CAAC;IAuB1E,uFAAuF;IACvF,GAAG,CAAC,KAAK,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,GAAG,IAAI;IAKtC,sFAAsF;IACtF,WAAW,CAAC,KAAK,EAAE,MAAM,GAAG,MAAM,GAAG,SAAS;CAG/C"}
|