@ai-ecoverse/slicc-agent 3.52.1 → 4.0.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/README.md +17 -13
- package/dist/client.js +1 -1
- package/dist/client.js.map +1 -1
- package/dist/host.js.map +1 -1
- package/dist/index.js +0 -3
- package/dist/index.js.map +2 -2
- package/dist/main.js +95 -22
- package/dist/main.js.map +2 -2
- package/dist/mcp/accounts.js +18 -14
- package/dist/mcp/accounts.js.map +2 -2
- package/dist/mcp/connection.js +0 -2
- package/dist/mcp/connection.js.map +2 -2
- package/dist/mcp/credentials.js +6 -15
- package/dist/mcp/credentials.js.map +2 -2
- package/dist/mcp/index.js +0 -1
- package/dist/mcp/index.js.map +2 -2
- package/dist/mcp/oauth.js +15 -20
- package/dist/mcp/oauth.js.map +2 -2
- package/dist/mcp/runtime.js +36 -14
- package/dist/mcp/runtime.js.map +2 -2
- package/dist/mcp/tools.js +4 -6
- package/dist/mcp/tools.js.map +2 -2
- package/dist/models/index.js +7 -4
- package/dist/models/index.js.map +2 -2
- package/dist/monitor/index.js +5 -10
- package/dist/monitor/index.js.map +2 -2
- package/dist/monitor/redact.js +4 -5
- package/dist/monitor/redact.js.map +2 -2
- package/dist/secrets/credentials.js +32 -0
- package/dist/secrets/credentials.js.map +7 -0
- package/dist/secrets/endpoints.js +111 -0
- package/dist/secrets/endpoints.js.map +7 -0
- package/dist/secrets/fetch.js +160 -0
- package/dist/secrets/fetch.js.map +7 -0
- package/dist/secrets/records.js +35 -0
- package/dist/secrets/records.js.map +7 -0
- package/dist/secrets/store.js +50 -0
- package/dist/secrets/store.js.map +7 -0
- package/dist/secrets/vault.js +58 -13
- package/dist/secrets/vault.js.map +2 -2
- package/dist/services.js.map +2 -2
- package/dist/settings.js +85 -23
- package/dist/settings.js.map +2 -2
- package/dist/spectrum/settings-port.js +24 -6
- package/dist/spectrum/settings-port.js.map +2 -2
- package/dist/types/host.d.ts +1 -1
- package/dist/types/index.d.ts +0 -1
- package/dist/types/main.d.ts +7 -2
- package/dist/types/mcp/accounts.d.ts +10 -4
- package/dist/types/mcp/connection.d.ts +0 -2
- package/dist/types/mcp/credentials.d.ts +6 -4
- package/dist/types/mcp/oauth.d.ts +3 -2
- package/dist/types/mcp/runtime.d.ts +18 -4
- package/dist/types/models/index.d.ts +2 -0
- package/dist/types/monitor/index.d.ts +0 -1
- package/dist/types/monitor/redact.d.ts +2 -2
- package/dist/types/secrets/credentials.d.ts +5 -0
- package/dist/types/secrets/endpoints.d.ts +27 -0
- package/dist/types/secrets/fetch.d.ts +13 -0
- package/dist/types/secrets/records.d.ts +13 -0
- package/dist/types/secrets/store.d.ts +7 -0
- package/dist/types/secrets/vault.d.ts +31 -1
- package/dist/types/services.d.ts +8 -1
- package/dist/types/settings.d.ts +17 -2
- package/dist/types/spectrum/settings-port.d.ts +6 -4
- package/package.json +5 -3
- package/dist/credentials.js +0 -100
- package/dist/credentials.js.map +0 -7
- package/dist/types/credentials.d.ts +0 -12
|
@@ -0,0 +1,160 @@
|
|
|
1
|
+
import { VaultRefusal } from "./vault.js";
|
|
2
|
+
const BODYLESS = /* @__PURE__ */ new Set(["GET", "HEAD"]);
|
|
3
|
+
const MIN_PART = 8;
|
|
4
|
+
function absent(vault) {
|
|
5
|
+
return !vault.connected && !vault.needed;
|
|
6
|
+
}
|
|
7
|
+
async function outgoing(request) {
|
|
8
|
+
const body = BODYLESS.has(request.method) ? void 0 : new Uint8Array(await request.arrayBuffer());
|
|
9
|
+
return {
|
|
10
|
+
method: request.method,
|
|
11
|
+
url: request.url,
|
|
12
|
+
headers: [...request.headers],
|
|
13
|
+
...body ? { body } : {}
|
|
14
|
+
};
|
|
15
|
+
}
|
|
16
|
+
function refusal(error) {
|
|
17
|
+
const code = error instanceof VaultRefusal ? error.code : void 0;
|
|
18
|
+
const status = code === "EACCES" ? 403 : code === "EINVAL" ? 400 : 503;
|
|
19
|
+
const text = error instanceof Error ? error.message : String(error);
|
|
20
|
+
return new Response(text, {
|
|
21
|
+
status,
|
|
22
|
+
headers: { "content-type": "text/plain; charset=utf-8" }
|
|
23
|
+
});
|
|
24
|
+
}
|
|
25
|
+
async function prepared(op, request) {
|
|
26
|
+
try {
|
|
27
|
+
return await op.prepare(request);
|
|
28
|
+
} catch (error) {
|
|
29
|
+
if (error instanceof VaultRefusal && error.code === "EAGAIN") return op.prepare(request);
|
|
30
|
+
throw error;
|
|
31
|
+
}
|
|
32
|
+
}
|
|
33
|
+
function filled(original, ready) {
|
|
34
|
+
const sent2 = new Set(original.headers.map(([, value]) => value));
|
|
35
|
+
const values = ready.headers.map(([, value]) => value).filter((value) => !sent2.has(value));
|
|
36
|
+
if (ready.url !== original.url) values.push(ready.url, decodeURIComponent(ready.url));
|
|
37
|
+
return values.flatMap((value) => [
|
|
38
|
+
value,
|
|
39
|
+
...value.split(/[\s=&?]+/).filter((part) => part.length >= MIN_PART)
|
|
40
|
+
]);
|
|
41
|
+
}
|
|
42
|
+
function safeError(error, original, ready) {
|
|
43
|
+
if (error instanceof DOMException && (error.name === "AbortError" || error.name === "TimeoutError"))
|
|
44
|
+
return error;
|
|
45
|
+
const text = error instanceof Error ? error.message : String(error);
|
|
46
|
+
const parts = filled(original, ready);
|
|
47
|
+
const shown = parts.some((part) => text.includes(part)) ? "the request failed" : text;
|
|
48
|
+
return new TypeError(`${ready.method} ${new URL(ready.url).origin}: ${shown}`);
|
|
49
|
+
}
|
|
50
|
+
async function sent(inner, request, original, ready) {
|
|
51
|
+
const init = {
|
|
52
|
+
method: ready.method,
|
|
53
|
+
headers: ready.headers,
|
|
54
|
+
signal: request.signal,
|
|
55
|
+
redirect: request.redirect,
|
|
56
|
+
credentials: request.credentials,
|
|
57
|
+
...ready.body === void 0 ? {} : { body: ready.body }
|
|
58
|
+
};
|
|
59
|
+
try {
|
|
60
|
+
return await inner(ready.url, init);
|
|
61
|
+
} catch (error) {
|
|
62
|
+
throw safeError(error, original, ready);
|
|
63
|
+
}
|
|
64
|
+
}
|
|
65
|
+
async function through(op, inner, request) {
|
|
66
|
+
const original = await outgoing(request);
|
|
67
|
+
let refreshed = false;
|
|
68
|
+
for (; ; ) {
|
|
69
|
+
let ready;
|
|
70
|
+
try {
|
|
71
|
+
ready = await prepared(op, original);
|
|
72
|
+
} catch (error) {
|
|
73
|
+
return refusal(error);
|
|
74
|
+
}
|
|
75
|
+
const response = await sent(inner, request, original, ready);
|
|
76
|
+
if (response.status !== 401 || refreshed || !op.refresh) return response;
|
|
77
|
+
refreshed = true;
|
|
78
|
+
if (!await op.refresh().then(
|
|
79
|
+
() => true,
|
|
80
|
+
() => false
|
|
81
|
+
))
|
|
82
|
+
return response;
|
|
83
|
+
await response.body?.cancel().catch(() => void 0);
|
|
84
|
+
}
|
|
85
|
+
}
|
|
86
|
+
function vaultFetch(vault, inner, route) {
|
|
87
|
+
return async (input, init) => {
|
|
88
|
+
const request = new Request(input, init);
|
|
89
|
+
const provider = absent(vault) ? void 0 : route(request);
|
|
90
|
+
if (provider === void 0) return inner(request);
|
|
91
|
+
const target = provider === null ? void 0 : { provider };
|
|
92
|
+
return through(
|
|
93
|
+
{
|
|
94
|
+
prepare: (outgoing2) => vault.model(provider ?? void 0, outgoing2),
|
|
95
|
+
...target ? { refresh: () => vault.refresh(target) } : {}
|
|
96
|
+
},
|
|
97
|
+
inner,
|
|
98
|
+
request
|
|
99
|
+
);
|
|
100
|
+
};
|
|
101
|
+
}
|
|
102
|
+
function mcpFetch(vault, inner, server) {
|
|
103
|
+
return async (input, init) => {
|
|
104
|
+
const request = new Request(input, init);
|
|
105
|
+
if (absent(vault)) return inner(request);
|
|
106
|
+
return through(
|
|
107
|
+
{
|
|
108
|
+
prepare: (outgoing2) => vault.mcp(server, outgoing2),
|
|
109
|
+
refresh: () => vault.refresh({ server })
|
|
110
|
+
},
|
|
111
|
+
inner,
|
|
112
|
+
request
|
|
113
|
+
);
|
|
114
|
+
};
|
|
115
|
+
}
|
|
116
|
+
const NO_VAULT_SIGN_IN = "MCP sign-in needs seven's vault: update seven";
|
|
117
|
+
function oauthOf(url, params) {
|
|
118
|
+
const scope = params.get("scope");
|
|
119
|
+
const resource = params.get("resource");
|
|
120
|
+
return {
|
|
121
|
+
tokenUrl: url,
|
|
122
|
+
clientId: params.get("client_id") ?? "",
|
|
123
|
+
...scope ? { scope } : {},
|
|
124
|
+
...resource ? { resource } : {}
|
|
125
|
+
};
|
|
126
|
+
}
|
|
127
|
+
function grantFetch(vault, server, base) {
|
|
128
|
+
return async (input, init) => {
|
|
129
|
+
const request = new Request(input, init);
|
|
130
|
+
const params = request.method === "POST" ? new URLSearchParams(await request.clone().text()) : void 0;
|
|
131
|
+
if (params?.get("grant_type") !== "authorization_code") return base(request);
|
|
132
|
+
if (absent(vault)) throw new Error(NO_VAULT_SIGN_IN);
|
|
133
|
+
const response = await base(request);
|
|
134
|
+
if (!response.ok) return response;
|
|
135
|
+
const raw = new Uint8Array(await response.arrayBuffer());
|
|
136
|
+
try {
|
|
137
|
+
const granted = await vault.grant(server, raw, oauthOf(request.url, params));
|
|
138
|
+
return new Response(granted.response, {
|
|
139
|
+
status: response.status,
|
|
140
|
+
headers: { "content-type": "application/json" }
|
|
141
|
+
});
|
|
142
|
+
} catch (error) {
|
|
143
|
+
throw new Error(
|
|
144
|
+
`the vault didn't keep the sign-in: ${error instanceof Error ? error.message : String(error)}`
|
|
145
|
+
);
|
|
146
|
+
} finally {
|
|
147
|
+
raw.fill(0);
|
|
148
|
+
}
|
|
149
|
+
};
|
|
150
|
+
}
|
|
151
|
+
export {
|
|
152
|
+
NO_VAULT_SIGN_IN,
|
|
153
|
+
absent,
|
|
154
|
+
grantFetch,
|
|
155
|
+
mcpFetch,
|
|
156
|
+
refusal,
|
|
157
|
+
safeError,
|
|
158
|
+
vaultFetch
|
|
159
|
+
};
|
|
160
|
+
//# sourceMappingURL=fetch.js.map
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
{
|
|
2
|
+
"version": 3,
|
|
3
|
+
"sources": ["../../src/secrets/fetch.ts"],
|
|
4
|
+
"sourcesContent": ["import type { OAuthConfig, OutgoingRequest } from '@ai-ecoverse/slicc-vault';\nimport { type RefreshTarget, type Vault, VaultRefusal } from './vault.ts';\n\ntype Fetch = typeof fetch;\n\ntype Port = Pick<Vault, 'connected' | 'needed' | 'model' | 'mcp' | 'refresh' | 'grant'>;\n\nexport type ModelRoute = (request: Request) => string | null | undefined;\n\ninterface Op {\n prepare(request: OutgoingRequest): Promise<OutgoingRequest>;\n refresh?(): Promise<unknown>;\n}\n\nconst BODYLESS = new Set(['GET', 'HEAD']);\nconst MIN_PART = 8;\n\nexport function absent(vault: Pick<Vault, 'connected' | 'needed'>): boolean {\n return !vault.connected && !vault.needed;\n}\n\nasync function outgoing(request: Request): Promise<OutgoingRequest> {\n const body = BODYLESS.has(request.method)\n ? undefined\n : new Uint8Array(await request.arrayBuffer());\n return {\n method: request.method,\n url: request.url,\n headers: [...request.headers],\n ...(body ? { body } : {}),\n };\n}\n\nexport function refusal(error: unknown): Response {\n const code = error instanceof VaultRefusal ? error.code : undefined;\n const status = code === 'EACCES' ? 403 : code === 'EINVAL' ? 400 : 503;\n const text = error instanceof Error ? error.message : String(error);\n return new Response(text, {\n status,\n headers: { 'content-type': 'text/plain; charset=utf-8' },\n });\n}\n\nasync function prepared(op: Op, request: OutgoingRequest): Promise<OutgoingRequest> {\n try {\n return await op.prepare(request);\n } catch (error) {\n if (error instanceof VaultRefusal && error.code === 'EAGAIN') return op.prepare(request);\n throw error;\n }\n}\n\nfunction filled(original: OutgoingRequest, ready: OutgoingRequest): string[] {\n const sent = new Set(original.headers.map(([, value]) => value));\n const values = ready.headers.map(([, value]) => value).filter((value) => !sent.has(value));\n if (ready.url !== original.url) values.push(ready.url, decodeURIComponent(ready.url));\n return values.flatMap((value) => [\n value,\n ...value.split(/[\\s=&?]+/).filter((part) => part.length >= MIN_PART),\n ]);\n}\n\nexport function safeError(error: unknown, original: OutgoingRequest, ready: OutgoingRequest) {\n if (\n error instanceof DOMException &&\n (error.name === 'AbortError' || error.name === 'TimeoutError')\n )\n return error;\n const text = error instanceof Error ? error.message : String(error);\n const parts = filled(original, ready);\n const shown = parts.some((part) => text.includes(part)) ? 'the request failed' : text;\n return new TypeError(`${ready.method} ${new URL(ready.url).origin}: ${shown}`);\n}\n\nasync function sent(\n inner: Fetch,\n request: Request,\n original: OutgoingRequest,\n ready: OutgoingRequest\n) {\n const init: RequestInit = {\n method: ready.method,\n headers: ready.headers,\n signal: request.signal,\n redirect: request.redirect,\n credentials: request.credentials,\n ...(ready.body === undefined ? {} : { body: ready.body as BodyInit }),\n };\n try {\n return await inner(ready.url, init);\n } catch (error) {\n throw safeError(error, original, ready);\n }\n}\n\nasync function through(op: Op, inner: Fetch, request: Request): Promise<Response> {\n const original = await outgoing(request);\n let refreshed = false;\n for (;;) {\n let ready: OutgoingRequest;\n try {\n ready = await prepared(op, original);\n } catch (error) {\n return refusal(error);\n }\n const response = await sent(inner, request, original, ready);\n if (response.status !== 401 || refreshed || !op.refresh) return response;\n refreshed = true;\n if (\n !(await op.refresh().then(\n () => true,\n () => false\n ))\n )\n return response;\n await response.body?.cancel().catch(() => undefined);\n }\n}\n\nexport function vaultFetch(vault: Port, inner: Fetch, route: ModelRoute): Fetch {\n return async (input, init) => {\n const request = new Request(input, init);\n const provider = absent(vault) ? undefined : route(request);\n if (provider === undefined) return inner(request);\n const target: RefreshTarget | undefined = provider === null ? undefined : { provider };\n return through(\n {\n prepare: (outgoing) => vault.model(provider ?? undefined, outgoing),\n ...(target ? { refresh: () => vault.refresh(target) } : {}),\n },\n inner,\n request\n );\n };\n}\n\nexport function mcpFetch(vault: Port, inner: Fetch, server: string): Fetch {\n return async (input, init) => {\n const request = new Request(input, init);\n if (absent(vault)) return inner(request);\n return through(\n {\n prepare: (outgoing) => vault.mcp(server, outgoing),\n refresh: () => vault.refresh({ server }),\n },\n inner,\n request\n );\n };\n}\n\nexport const NO_VAULT_SIGN_IN = \"MCP sign-in needs seven's vault: update seven\";\n\nfunction oauthOf(url: string, params: URLSearchParams): OAuthConfig {\n const scope = params.get('scope');\n const resource = params.get('resource');\n return {\n tokenUrl: url,\n clientId: params.get('client_id') ?? '',\n ...(scope ? { scope } : {}),\n ...(resource ? { resource } : {}),\n };\n}\n\nexport function grantFetch(vault: Port, server: string, base: Fetch): Fetch {\n return async (input, init) => {\n const request = new Request(input, init);\n const params =\n request.method === 'POST' ? new URLSearchParams(await request.clone().text()) : undefined;\n if (params?.get('grant_type') !== 'authorization_code') return base(request);\n if (absent(vault)) throw new Error(NO_VAULT_SIGN_IN);\n const response = await base(request);\n if (!response.ok) return response;\n const raw = new Uint8Array(await response.arrayBuffer());\n try {\n const granted = await vault.grant(server, raw, oauthOf(request.url, params));\n return new Response(granted.response as BodyInit, {\n status: response.status,\n headers: { 'content-type': 'application/json' },\n });\n } catch (error) {\n throw new Error(\n `the vault didn't keep the sign-in: ${error instanceof Error ? error.message : String(error)}`\n );\n } finally {\n raw.fill(0);\n }\n };\n}\n"],
|
|
5
|
+
"mappings": "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",
|
|
6
|
+
"names": ["sent", "outgoing"]
|
|
7
|
+
}
|
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
import { replicatedState } from "@earendil-works/chord";
|
|
2
|
+
function vaultRecords(vault) {
|
|
3
|
+
const state = replicatedState([]);
|
|
4
|
+
let version = vault.state.value.version;
|
|
5
|
+
let port = vault.state.value.port;
|
|
6
|
+
let lock = Promise.resolve();
|
|
7
|
+
const read = async () => vault.connected || vault.needed ? vault.records() : [];
|
|
8
|
+
const refresh = (context) => {
|
|
9
|
+
const run = lock.then(async () => state.replace(context, await read()));
|
|
10
|
+
lock = run.catch(() => void 0);
|
|
11
|
+
return run;
|
|
12
|
+
};
|
|
13
|
+
const off = vault.state.subscribe((value, context) => {
|
|
14
|
+
const bumped = value.version !== version || port === "none" && value.port !== "none";
|
|
15
|
+
version = value.version;
|
|
16
|
+
port = value.port;
|
|
17
|
+
if (bumped) void refresh(context).catch(() => void 0);
|
|
18
|
+
});
|
|
19
|
+
const of = (kind) => state.value.filter((record) => record.kind === kind);
|
|
20
|
+
return {
|
|
21
|
+
state,
|
|
22
|
+
refresh,
|
|
23
|
+
model: (provider) => of("model").find((record) => record.provider === provider),
|
|
24
|
+
mcp: (server, name) => {
|
|
25
|
+
const own = of("mcp").filter((record) => record.server === server);
|
|
26
|
+
if (name === void 0) return own[0];
|
|
27
|
+
return own.find((record) => record.name === name) ?? of("mcp").find((record) => record.server === void 0 && record.name === name);
|
|
28
|
+
},
|
|
29
|
+
close: off
|
|
30
|
+
};
|
|
31
|
+
}
|
|
32
|
+
export {
|
|
33
|
+
vaultRecords
|
|
34
|
+
};
|
|
35
|
+
//# sourceMappingURL=records.js.map
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
{
|
|
2
|
+
"version": 3,
|
|
3
|
+
"sources": ["../../src/secrets/records.ts"],
|
|
4
|
+
"sourcesContent": ["import type { AgentRecord } from '@ai-ecoverse/slicc-vault';\nimport { type Context, type MutableReplicatedState, replicatedState } from '@earendil-works/chord';\nimport type { Vault } from './vault.ts';\n\nexport type { AgentRecord } from '@ai-ecoverse/slicc-vault';\n\nexport interface VaultRecords {\n readonly state: MutableReplicatedState<AgentRecord[]>;\n refresh(context: Context): Promise<void>;\n model(provider: string): AgentRecord | undefined;\n mcp(server: string, name?: string): AgentRecord | undefined;\n close(): void;\n}\n\ntype Source = Pick<Vault, 'state' | 'records' | 'connected' | 'needed'>;\n\nexport function vaultRecords(vault: Source): VaultRecords {\n const state = replicatedState<AgentRecord[]>([]);\n let version = vault.state.value.version;\n let port = vault.state.value.port;\n let lock: Promise<unknown> = Promise.resolve();\n const read = async () => (vault.connected || vault.needed ? vault.records() : []);\n const refresh = (context: Context) => {\n const run = lock.then(async () => state.replace(context, await read()));\n lock = run.catch(() => undefined);\n return run;\n };\n const off = vault.state.subscribe((value, context) => {\n const bumped = value.version !== version || (port === 'none' && value.port !== 'none');\n version = value.version;\n port = value.port;\n if (bumped) void refresh(context).catch(() => undefined);\n });\n const of = (kind: AgentRecord['kind']) => state.value.filter((record) => record.kind === kind);\n return {\n state,\n refresh,\n model: (provider) => of('model').find((record) => record.provider === provider),\n mcp: (server, name) => {\n const own = of('mcp').filter((record) => record.server === server);\n if (name === undefined) return own[0];\n return (\n own.find((record) => record.name === name) ??\n of('mcp').find((record) => record.server === undefined && record.name === name)\n );\n },\n close: off,\n };\n}\n"],
|
|
5
|
+
"mappings": "AACA,SAAoD,uBAAuB;AAepE,SAAS,aAAa,OAA6B;AACxD,QAAM,QAAQ,gBAA+B,CAAC,CAAC;AAC/C,MAAI,UAAU,MAAM,MAAM,MAAM;AAChC,MAAI,OAAO,MAAM,MAAM,MAAM;AAC7B,MAAI,OAAyB,QAAQ,QAAQ;AAC7C,QAAM,OAAO,YAAa,MAAM,aAAa,MAAM,SAAS,MAAM,QAAQ,IAAI,CAAC;AAC/E,QAAM,UAAU,CAAC,YAAqB;AACpC,UAAM,MAAM,KAAK,KAAK,YAAY,MAAM,QAAQ,SAAS,MAAM,KAAK,CAAC,CAAC;AACtE,WAAO,IAAI,MAAM,MAAM,MAAS;AAChC,WAAO;AAAA,EACT;AACA,QAAM,MAAM,MAAM,MAAM,UAAU,CAAC,OAAO,YAAY;AACpD,UAAM,SAAS,MAAM,YAAY,WAAY,SAAS,UAAU,MAAM,SAAS;AAC/E,cAAU,MAAM;AAChB,WAAO,MAAM;AACb,QAAI,OAAQ,MAAK,QAAQ,OAAO,EAAE,MAAM,MAAM,MAAS;AAAA,EACzD,CAAC;AACD,QAAM,KAAK,CAAC,SAA8B,MAAM,MAAM,OAAO,CAAC,WAAW,OAAO,SAAS,IAAI;AAC7F,SAAO;AAAA,IACL;AAAA,IACA;AAAA,IACA,OAAO,CAAC,aAAa,GAAG,OAAO,EAAE,KAAK,CAAC,WAAW,OAAO,aAAa,QAAQ;AAAA,IAC9E,KAAK,CAAC,QAAQ,SAAS;AACrB,YAAM,MAAM,GAAG,KAAK,EAAE,OAAO,CAAC,WAAW,OAAO,WAAW,MAAM;AACjE,UAAI,SAAS,OAAW,QAAO,IAAI,CAAC;AACpC,aACE,IAAI,KAAK,CAAC,WAAW,OAAO,SAAS,IAAI,KACzC,GAAG,KAAK,EAAE,KAAK,CAAC,WAAW,OAAO,WAAW,UAAa,OAAO,SAAS,IAAI;AAAA,IAElF;AAAA,IACA,OAAO;AAAA,EACT;AACF;",
|
|
6
|
+
"names": []
|
|
7
|
+
}
|
|
@@ -0,0 +1,50 @@
|
|
|
1
|
+
import { BACKGROUND_CONTEXT } from "@earendil-works/chord/context";
|
|
2
|
+
function memoryStore() {
|
|
3
|
+
const values = /* @__PURE__ */ new Map();
|
|
4
|
+
return {
|
|
5
|
+
get: async (key) => structuredClone(values.get(key)),
|
|
6
|
+
async set(key, value) {
|
|
7
|
+
if (value === void 0) values.delete(key);
|
|
8
|
+
else values.set(key, structuredClone(value));
|
|
9
|
+
}
|
|
10
|
+
};
|
|
11
|
+
}
|
|
12
|
+
function fileStore(env, path) {
|
|
13
|
+
let cache;
|
|
14
|
+
let writes = Promise.resolve();
|
|
15
|
+
const load = () => {
|
|
16
|
+
cache ??= env.readTextFile(path, BACKGROUND_CONTEXT).then((read) => {
|
|
17
|
+
if (!read.ok) return {};
|
|
18
|
+
try {
|
|
19
|
+
const parsed = JSON.parse(read.value);
|
|
20
|
+
return parsed && typeof parsed === "object" ? parsed : {};
|
|
21
|
+
} catch {
|
|
22
|
+
return {};
|
|
23
|
+
}
|
|
24
|
+
});
|
|
25
|
+
return cache;
|
|
26
|
+
};
|
|
27
|
+
return {
|
|
28
|
+
async get(key) {
|
|
29
|
+
await writes;
|
|
30
|
+
return structuredClone((await load())[key]);
|
|
31
|
+
},
|
|
32
|
+
set(key, value) {
|
|
33
|
+
const write = writes.then(async () => {
|
|
34
|
+
const all = { ...await load() };
|
|
35
|
+
if (value === void 0) delete all[key];
|
|
36
|
+
else all[key] = structuredClone(value);
|
|
37
|
+
cache = Promise.resolve(all);
|
|
38
|
+
const wrote = await env.writeFile(path, JSON.stringify(all), BACKGROUND_CONTEXT);
|
|
39
|
+
if (!wrote.ok) throw new Error(`can't write ${path}`);
|
|
40
|
+
});
|
|
41
|
+
writes = write.catch(() => void 0);
|
|
42
|
+
return write;
|
|
43
|
+
}
|
|
44
|
+
};
|
|
45
|
+
}
|
|
46
|
+
export {
|
|
47
|
+
fileStore,
|
|
48
|
+
memoryStore
|
|
49
|
+
};
|
|
50
|
+
//# sourceMappingURL=store.js.map
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
{
|
|
2
|
+
"version": 3,
|
|
3
|
+
"sources": ["../../src/secrets/store.ts"],
|
|
4
|
+
"sourcesContent": ["import { BACKGROUND_CONTEXT } from '@earendil-works/chord/context';\nimport type { ExecutionEnv } from '@earendil-works/pi-durable/env';\n\nexport interface PlainStore {\n get(key: string): Promise<unknown>;\n set(key: string, value: unknown): Promise<void>;\n}\n\nexport function memoryStore(): PlainStore {\n const values = new Map<string, unknown>();\n return {\n get: async (key) => structuredClone(values.get(key)),\n async set(key, value) {\n if (value === undefined) values.delete(key);\n else values.set(key, structuredClone(value));\n },\n };\n}\n\nexport function fileStore(env: ExecutionEnv, path: string): PlainStore {\n let cache: Promise<Record<string, unknown>> | undefined;\n let writes: Promise<unknown> = Promise.resolve();\n const load = () => {\n cache ??= env.readTextFile(path, BACKGROUND_CONTEXT).then((read) => {\n if (!read.ok) return {};\n try {\n const parsed: unknown = JSON.parse(read.value);\n return parsed && typeof parsed === 'object' ? (parsed as Record<string, unknown>) : {};\n } catch {\n return {};\n }\n });\n return cache;\n };\n return {\n async get(key) {\n await writes;\n return structuredClone((await load())[key]);\n },\n set(key, value) {\n const write = writes.then(async () => {\n const all = { ...(await load()) };\n if (value === undefined) delete all[key];\n else all[key] = structuredClone(value);\n cache = Promise.resolve(all);\n const wrote = await env.writeFile(path, JSON.stringify(all), BACKGROUND_CONTEXT);\n if (!wrote.ok) throw new Error(`can't write ${path}`);\n });\n writes = write.catch(() => undefined);\n return write;\n },\n };\n}\n"],
|
|
5
|
+
"mappings": "AAAA,SAAS,0BAA0B;AAQ5B,SAAS,cAA0B;AACxC,QAAM,SAAS,oBAAI,IAAqB;AACxC,SAAO;AAAA,IACL,KAAK,OAAO,QAAQ,gBAAgB,OAAO,IAAI,GAAG,CAAC;AAAA,IACnD,MAAM,IAAI,KAAK,OAAO;AACpB,UAAI,UAAU,OAAW,QAAO,OAAO,GAAG;AAAA,UACrC,QAAO,IAAI,KAAK,gBAAgB,KAAK,CAAC;AAAA,IAC7C;AAAA,EACF;AACF;AAEO,SAAS,UAAU,KAAmB,MAA0B;AACrE,MAAI;AACJ,MAAI,SAA2B,QAAQ,QAAQ;AAC/C,QAAM,OAAO,MAAM;AACjB,cAAU,IAAI,aAAa,MAAM,kBAAkB,EAAE,KAAK,CAAC,SAAS;AAClE,UAAI,CAAC,KAAK,GAAI,QAAO,CAAC;AACtB,UAAI;AACF,cAAM,SAAkB,KAAK,MAAM,KAAK,KAAK;AAC7C,eAAO,UAAU,OAAO,WAAW,WAAY,SAAqC,CAAC;AAAA,MACvF,QAAQ;AACN,eAAO,CAAC;AAAA,MACV;AAAA,IACF,CAAC;AACD,WAAO;AAAA,EACT;AACA,SAAO;AAAA,IACL,MAAM,IAAI,KAAK;AACb,YAAM;AACN,aAAO,iBAAiB,MAAM,KAAK,GAAG,GAAG,CAAC;AAAA,IAC5C;AAAA,IACA,IAAI,KAAK,OAAO;AACd,YAAM,QAAQ,OAAO,KAAK,YAAY;AACpC,cAAM,MAAM,EAAE,GAAI,MAAM,KAAK,EAAG;AAChC,YAAI,UAAU,OAAW,QAAO,IAAI,GAAG;AAAA,YAClC,KAAI,GAAG,IAAI,gBAAgB,KAAK;AACrC,gBAAQ,QAAQ,QAAQ,GAAG;AAC3B,cAAM,QAAQ,MAAM,IAAI,UAAU,MAAM,KAAK,UAAU,GAAG,GAAG,kBAAkB;AAC/E,YAAI,CAAC,MAAM,GAAI,OAAM,IAAI,MAAM,eAAe,IAAI,EAAE;AAAA,MACtD,CAAC;AACD,eAAS,MAAM,MAAM,MAAM,MAAS;AACpC,aAAO;AAAA,IACT;AAAA,EACF;AACF;",
|
|
6
|
+
"names": []
|
|
7
|
+
}
|
package/dist/secrets/vault.js
CHANGED
|
@@ -3,6 +3,14 @@ import { BACKGROUND_CONTEXT } from "@earendil-works/chord/context";
|
|
|
3
3
|
import { vaultHold } from "./view.js";
|
|
4
4
|
const WAITING_MS = 2e3;
|
|
5
5
|
const WAITING = "waiting for the vault";
|
|
6
|
+
class VaultRefusal extends Error {
|
|
7
|
+
code;
|
|
8
|
+
constructor(code, message) {
|
|
9
|
+
super(message);
|
|
10
|
+
this.name = "VaultRefusal";
|
|
11
|
+
this.code = code;
|
|
12
|
+
}
|
|
13
|
+
}
|
|
6
14
|
const LOCKS = ["no", "scrubbing", "passkey"];
|
|
7
15
|
const EMPTY = new Uint8Array();
|
|
8
16
|
function pairOf(value) {
|
|
@@ -23,6 +31,7 @@ class Vault {
|
|
|
23
31
|
#seen = 0;
|
|
24
32
|
#serial = 0;
|
|
25
33
|
#streamSerial = 0;
|
|
34
|
+
#tag = Math.random().toString(36).slice(2, 10);
|
|
26
35
|
constructor(now = Date.now) {
|
|
27
36
|
this.#now = now;
|
|
28
37
|
this.state = replicatedState(this.#snapshot());
|
|
@@ -30,9 +39,13 @@ class Vault {
|
|
|
30
39
|
get needed() {
|
|
31
40
|
return this.#pair.needed || this.#seen > this.#pair.version;
|
|
32
41
|
}
|
|
33
|
-
|
|
42
|
+
get connected() {
|
|
43
|
+
return this.#port !== void 0;
|
|
44
|
+
}
|
|
45
|
+
connect(port, scrub, locked) {
|
|
34
46
|
const pair = scrub === void 0 ? void 0 : pairOf(scrub);
|
|
35
47
|
if (pair) this.#pair = pair;
|
|
48
|
+
if (typeof locked === "boolean") this.#locked = locked ? "passkey" : "no";
|
|
36
49
|
if (port && port !== this.#port) {
|
|
37
50
|
if (this.#port) this.#port.onmessage = null;
|
|
38
51
|
this.#port = port;
|
|
@@ -57,21 +70,45 @@ class Vault {
|
|
|
57
70
|
const answer = await this.#call("redact", { texts: [...texts] });
|
|
58
71
|
return answer.texts;
|
|
59
72
|
}
|
|
73
|
+
async model(provider, request) {
|
|
74
|
+
const fields = provider === void 0 ? { request } : { provider, request };
|
|
75
|
+
return (await this.#call("model", fields)).request;
|
|
76
|
+
}
|
|
77
|
+
async mcp(server, request) {
|
|
78
|
+
return (await this.#call("mcp", { server, request })).request;
|
|
79
|
+
}
|
|
80
|
+
async records() {
|
|
81
|
+
return (await this.#call("records", {})).records;
|
|
82
|
+
}
|
|
83
|
+
async grant(server, response, oauth, name) {
|
|
84
|
+
const fields = { server, response, oauth, ...name === void 0 ? {} : { name } };
|
|
85
|
+
const { response: shown, records, expiresAt } = await this.#call("grant", fields);
|
|
86
|
+
return { response: shown, records, ...expiresAt === void 0 ? {} : { expiresAt } };
|
|
87
|
+
}
|
|
88
|
+
async refresh(target, name) {
|
|
89
|
+
const fields = { ...target, ...name === void 0 ? {} : { name } };
|
|
90
|
+
return (await this.#call("refresh", fields)).state;
|
|
91
|
+
}
|
|
92
|
+
async endpoints(set) {
|
|
93
|
+
await this.#call("endpoints", { model: set.model, mcp: set.mcp });
|
|
94
|
+
}
|
|
60
95
|
stream() {
|
|
61
96
|
let stream;
|
|
62
97
|
return {
|
|
63
98
|
push: (chunk) => {
|
|
64
99
|
if (stream === void 0 && !this.needed) return Promise.resolve(chunk);
|
|
65
100
|
if (stream === void 0) {
|
|
66
|
-
stream = ++this.#streamSerial
|
|
101
|
+
stream = `${this.#tag}-${++this.#streamSerial}`;
|
|
67
102
|
this.#streams.add(stream);
|
|
68
103
|
void this.#call("redactStream", { stream });
|
|
69
104
|
}
|
|
70
|
-
return this.#call("push", { stream, chunk })
|
|
105
|
+
return this.#call("push", { stream, chunk }).then(
|
|
106
|
+
(answer) => answer.chunk
|
|
107
|
+
);
|
|
71
108
|
},
|
|
72
109
|
end: async () => {
|
|
73
110
|
if (stream === void 0) return EMPTY;
|
|
74
|
-
const tail = await this.#call("end", { stream });
|
|
111
|
+
const { chunk: tail } = await this.#call("end", { stream });
|
|
75
112
|
this.#streams.delete(stream);
|
|
76
113
|
return tail;
|
|
77
114
|
},
|
|
@@ -82,14 +119,14 @@ class Vault {
|
|
|
82
119
|
for (const [id, item] of this.#pending)
|
|
83
120
|
if (item.message.stream === dropped && item.message.op !== "redactStream") {
|
|
84
121
|
this.#pending.delete(id);
|
|
85
|
-
item.resolve(EMPTY);
|
|
122
|
+
item.resolve({ chunk: EMPTY });
|
|
86
123
|
}
|
|
87
124
|
void this.#call("drop", { stream: dropped });
|
|
88
125
|
}
|
|
89
126
|
};
|
|
90
127
|
}
|
|
91
128
|
#call(op, fields) {
|
|
92
|
-
const message = { id: ++this.#serial, op, ...fields };
|
|
129
|
+
const message = { v: 1, id: ++this.#serial, op, ...fields };
|
|
93
130
|
const result = new Promise((resolve, reject) => {
|
|
94
131
|
this.#pending.set(message.id, { message, at: this.#now(), resolve, reject });
|
|
95
132
|
});
|
|
@@ -103,16 +140,23 @@ class Vault {
|
|
|
103
140
|
const pair = "scrub" in data ? pairOf(data.scrub) : void 0;
|
|
104
141
|
if (pair) this.#pair = pair;
|
|
105
142
|
if (LOCKS.includes(data.locked)) this.#locked = data.locked;
|
|
143
|
+
if (data.op === "welcome") this.#welcome(data.status);
|
|
106
144
|
const item = typeof data.id === "number" ? this.#pending.get(data.id) : void 0;
|
|
107
145
|
if (item) {
|
|
108
146
|
this.#pending.delete(data.id);
|
|
109
|
-
|
|
110
|
-
if (
|
|
111
|
-
|
|
112
|
-
else item.resolve(data
|
|
147
|
+
if (typeof data.version === "number") this.#seen = Math.max(this.#seen, data.version);
|
|
148
|
+
if (data.error)
|
|
149
|
+
item.reject(new VaultRefusal(data.error.code, data.error.message ?? "the vault refused"));
|
|
150
|
+
else item.resolve(data);
|
|
113
151
|
}
|
|
114
152
|
this.#refresh();
|
|
115
153
|
}
|
|
154
|
+
#welcome(status) {
|
|
155
|
+
const given = status;
|
|
156
|
+
const pair = given && "scrub" in given ? pairOf(given.scrub) : void 0;
|
|
157
|
+
if (pair) this.#pair = pair;
|
|
158
|
+
if (typeof given?.locked === "boolean") this.#locked = given.locked ? "passkey" : "no";
|
|
159
|
+
}
|
|
116
160
|
#waiting() {
|
|
117
161
|
const now = this.#now();
|
|
118
162
|
return [...this.#pending.values()].some((item) => now - item.at >= WAITING_MS);
|
|
@@ -147,13 +191,14 @@ function holdText(state) {
|
|
|
147
191
|
function listenVault(scope, vault) {
|
|
148
192
|
scope.addEventListener("message", ({ data }) => {
|
|
149
193
|
const message = data;
|
|
150
|
-
if (!message || typeof message !== "object"
|
|
151
|
-
|
|
152
|
-
vault.connect(message.vault, message.scrub);
|
|
194
|
+
if (!message || typeof message !== "object") return;
|
|
195
|
+
if (!("vault" in message || "scrub" in message || "locked" in message)) return;
|
|
196
|
+
vault.connect(message.vault, message.scrub, message.locked);
|
|
153
197
|
});
|
|
154
198
|
}
|
|
155
199
|
export {
|
|
156
200
|
Vault,
|
|
201
|
+
VaultRefusal,
|
|
157
202
|
WAITING,
|
|
158
203
|
WAITING_MS,
|
|
159
204
|
holdText,
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"version": 3,
|
|
3
3
|
"sources": ["../../src/secrets/vault.ts"],
|
|
4
|
-
"sourcesContent": ["import { type MutableReplicatedState, replicatedState } from '@earendil-works/chord';\nimport { BACKGROUND_CONTEXT } from '@earendil-works/chord/context';\nimport type { Scrub, Scrubbable, ScrubStream } from './scrub.ts';\nimport { vaultHold } from './view.ts';\n\nexport type ScrubPair = { needed: boolean; version: number };\nexport type Locked = 'no' | 'scrubbing' | 'passkey';\n\nexport interface VaultState {\n port: 'none' | 'ready' | 'waiting';\n needed: boolean;\n version: number;\n locked: Locked;\n held: number;\n}\n\nexport const WAITING_MS = 2000;\nexport const WAITING = 'waiting for the vault';\n\ntype Message = Record<string, unknown> & { id: number; op: string };\n\ninterface Pending {\n message: Message;\n at: number;\n resolve(value: unknown): void;\n reject(error: Error): void;\n}\n\ntype Answer = {\n id?: unknown;\n ok?: unknown;\n error?: { message?: string };\n scrub?: unknown;\n locked?: unknown;\n};\n\nconst LOCKS: readonly unknown[] = ['no', 'scrubbing', 'passkey'];\n\nconst EMPTY = new Uint8Array();\n\nfunction pairOf(value: unknown): ScrubPair | undefined {\n const pair = value as Partial<ScrubPair> | null;\n if (pair === null) return { needed: false, version: 0 };\n if (typeof pair?.needed !== 'boolean' || typeof pair.version !== 'number') return undefined;\n return { needed: pair.needed, version: pair.version };\n}\n\nexport class Vault implements Scrub {\n readonly state: MutableReplicatedState<VaultState>;\n readonly #pending = new Map<number, Pending>();\n readonly #streams = new Set<number>();\n readonly #waiters = new Set<() => void>();\n readonly #now: () => number;\n #port: MessagePort | undefined;\n #pair: ScrubPair = { needed: false, version: 0 };\n #locked: Locked = 'no';\n #seen = 0;\n #serial = 0;\n #streamSerial = 0;\n\n constructor(now: () => number = Date.now) {\n this.#now = now;\n this.state = replicatedState<VaultState>(this.#snapshot());\n }\n\n get needed(): boolean {\n return this.#pair.needed || this.#seen > this.#pair.version;\n }\n\n connect(port: MessagePort | undefined, scrub: unknown): void {\n const pair = scrub === undefined ? undefined : pairOf(scrub);\n if (pair) this.#pair = pair;\n if (port && port !== this.#port) {\n if (this.#port) this.#port.onmessage = null;\n this.#port = port;\n port.onmessage = (event) => this.#answer(event.data as Answer);\n port.start?.();\n const resend = [...this.#pending.values()];\n const opening = new Set(\n resend\n .filter((item) => item.message.op === 'redactStream')\n .map((item) => item.message.stream)\n );\n for (const stream of this.#streams)\n if (!opening.has(stream)) void this.#call('redactStream', { stream });\n for (const item of resend) port.postMessage(item.message);\n }\n this.#refresh();\n }\n\n ready(): Promise<void> {\n if (!this.#holding()) return Promise.resolve();\n return new Promise((resolve) => this.#waiters.add(resolve));\n }\n\n async texts<T extends Scrubbable>(texts: readonly T[]): Promise<T[]> {\n if (!this.needed) return [...texts];\n const answer = (await this.#call('redact', { texts: [...texts] })) as {\n texts: T[];\n version?: number;\n };\n return answer.texts;\n }\n\n stream(): ScrubStream {\n let stream: number | undefined;\n return {\n push: (chunk) => {\n if (stream === undefined && !this.needed) return Promise.resolve(chunk);\n if (stream === undefined) {\n stream = ++this.#streamSerial;\n this.#streams.add(stream);\n void this.#call('redactStream', { stream });\n }\n return this.#call('push', { stream, chunk }) as Promise<Uint8Array>;\n },\n end: async () => {\n if (stream === undefined) return EMPTY;\n const tail = (await this.#call('end', { stream })) as Uint8Array;\n this.#streams.delete(stream);\n return tail;\n },\n drop: () => {\n if (stream === undefined) return;\n const dropped = stream;\n this.#streams.delete(dropped);\n for (const [id, item] of this.#pending)\n if (item.message.stream === dropped && item.message.op !== 'redactStream') {\n this.#pending.delete(id);\n item.resolve(EMPTY);\n }\n void this.#call('drop', { stream: dropped });\n },\n };\n }\n\n #call(op: string, fields: Record<string, unknown>): Promise<unknown> {\n const message: Message = { id: ++this.#serial, op, ...fields };\n const result = new Promise((resolve, reject) => {\n this.#pending.set(message.id, { message, at: this.#now(), resolve, reject });\n });\n this.#port?.postMessage(message);\n setTimeout(() => this.#refresh(), WAITING_MS);\n this.#refresh();\n return result;\n }\n\n #answer(data: Answer): void {\n if (!data || typeof data !== 'object') return;\n const pair = 'scrub' in data ? pairOf(data.scrub) : undefined;\n if (pair) this.#pair = pair;\n if (LOCKS.includes(data.locked)) this.#locked = data.locked as Locked;\n const item = typeof data.id === 'number' ? this.#pending.get(data.id) : undefined;\n if (item) {\n this.#pending.delete(data.id as number);\n const version = (data.ok as { version?: unknown } | undefined)?.version;\n if (typeof version === 'number') this.#seen = Math.max(this.#seen, version);\n if (data.error) item.reject(new Error(data.error.message ?? 'the vault refused'));\n else item.resolve(data.ok);\n }\n this.#refresh();\n }\n\n #waiting(): boolean {\n const now = this.#now();\n return [...this.#pending.values()].some((item) => now - item.at >= WAITING_MS);\n }\n\n #holding(): boolean {\n return this.needed && (!this.#port || this.#waiting() || this.#locked === 'passkey');\n }\n\n #snapshot(): VaultState {\n return {\n port: !this.#port ? 'none' : this.#waiting() ? 'waiting' : 'ready',\n needed: this.needed,\n version: this.#pair.version,\n locked: this.#locked,\n held: this.#pending.size,\n };\n }\n\n #refresh(): void {\n const next = this.#snapshot();\n const before = this.state.value;\n if (Object.entries(next).some(([key, value]) => before[key as keyof VaultState] !== value))\n this.state.replace(BACKGROUND_CONTEXT, next);\n if (this.#holding()) return;\n for (const resolve of this.#waiters) resolve();\n this.#waiters.clear();\n }\n}\n\nexport function holdText(state: VaultState): string | undefined {\n const hold = vaultHold(state);\n if (!hold) return undefined;\n return hold.reason === 'locked' ? 'unlock the vault to continue' : WAITING;\n}\n\nexport function listenVault(\n scope: { addEventListener(type: 'message', listener: (event: MessageEvent) => void): void },\n vault: Vault\n): void {\n scope.addEventListener('message', ({ data }) => {\n const message = data as { vault?: MessagePort; scrub?: unknown } | null;\n if (!message || typeof message !== 'object' || !('vault' in message || 'scrub' in message))\n return;\n vault.connect(message.vault, message.scrub);\n });\n}\n"],
|
|
5
|
-
"mappings": "
|
|
4
|
+
"sourcesContent": ["import type { Hit } from '@ai-ecoverse/slicc-scrub';\nimport type {\n AgentRecord,\n ErrorCode,\n McpServerEntry,\n ModelEndpoint,\n OAuthConfig,\n OutgoingRequest,\n} from '@ai-ecoverse/slicc-vault';\nimport { type MutableReplicatedState, replicatedState } from '@earendil-works/chord';\nimport { BACKGROUND_CONTEXT } from '@earendil-works/chord/context';\nimport type { Scrub, Scrubbable, ScrubStream } from './scrub.ts';\nimport { vaultHold } from './view.ts';\n\nexport type ScrubPair = { needed: boolean; version: number };\nexport type Locked = 'no' | 'scrubbing' | 'passkey';\n\nexport interface VaultState {\n port: 'none' | 'ready' | 'waiting';\n needed: boolean;\n version: number;\n locked: Locked;\n held: number;\n}\n\nexport const WAITING_MS = 2000;\nexport const WAITING = 'waiting for the vault';\n\ntype Message = Record<string, unknown> & { v: 1; id: number; op: string };\n\nexport class VaultRefusal extends Error {\n readonly code: ErrorCode | undefined;\n\n constructor(code: ErrorCode | undefined, message: string) {\n super(message);\n this.name = 'VaultRefusal';\n this.code = code;\n }\n}\n\nexport type RefreshTarget = { server: string } | { provider: string };\n\nexport interface Granted {\n response: string | Uint8Array;\n records: { kind: string; name: string; placeholder: string }[];\n expiresAt?: number;\n}\n\nexport interface EndpointSet {\n model: ModelEndpoint[];\n mcp: McpServerEntry[];\n}\n\ninterface Pending {\n message: Message;\n at: number;\n resolve(value: unknown): void;\n reject(error: Error): void;\n}\n\ntype Answer = Record<string, unknown> & {\n id?: unknown;\n error?: { code?: ErrorCode; message?: string };\n scrub?: unknown;\n locked?: unknown;\n version?: unknown;\n};\n\nconst LOCKS: readonly unknown[] = ['no', 'scrubbing', 'passkey'];\n\nconst EMPTY = new Uint8Array();\n\nfunction pairOf(value: unknown): ScrubPair | undefined {\n const pair = value as Partial<ScrubPair> | null;\n if (pair === null) return { needed: false, version: 0 };\n if (typeof pair?.needed !== 'boolean' || typeof pair.version !== 'number') return undefined;\n return { needed: pair.needed, version: pair.version };\n}\n\nexport class Vault implements Scrub {\n readonly state: MutableReplicatedState<VaultState>;\n readonly #pending = new Map<number, Pending>();\n readonly #streams = new Set<string>();\n readonly #waiters = new Set<() => void>();\n readonly #now: () => number;\n #port: MessagePort | undefined;\n #pair: ScrubPair = { needed: false, version: 0 };\n #locked: Locked = 'no';\n #seen = 0;\n #serial = 0;\n #streamSerial = 0;\n readonly #tag = Math.random().toString(36).slice(2, 10);\n\n constructor(now: () => number = Date.now) {\n this.#now = now;\n this.state = replicatedState<VaultState>(this.#snapshot());\n }\n\n get needed(): boolean {\n return this.#pair.needed || this.#seen > this.#pair.version;\n }\n\n get connected(): boolean {\n return this.#port !== undefined;\n }\n\n connect(port: MessagePort | undefined, scrub: unknown, locked?: unknown): void {\n const pair = scrub === undefined ? undefined : pairOf(scrub);\n if (pair) this.#pair = pair;\n if (typeof locked === 'boolean') this.#locked = locked ? 'passkey' : 'no';\n if (port && port !== this.#port) {\n if (this.#port) this.#port.onmessage = null;\n this.#port = port;\n port.onmessage = (event) => this.#answer(event.data as Answer);\n port.start?.();\n const resend = [...this.#pending.values()];\n const opening = new Set(\n resend\n .filter((item) => item.message.op === 'redactStream')\n .map((item) => item.message.stream)\n );\n for (const stream of this.#streams)\n if (!opening.has(stream)) void this.#call('redactStream', { stream });\n for (const item of resend) port.postMessage(item.message);\n }\n this.#refresh();\n }\n\n ready(): Promise<void> {\n if (!this.#holding()) return Promise.resolve();\n return new Promise((resolve) => this.#waiters.add(resolve));\n }\n\n async texts<T extends Scrubbable>(texts: readonly T[]): Promise<T[]> {\n if (!this.needed) return [...texts];\n const answer = (await this.#call('redact', { texts: [...texts] })) as {\n texts: T[];\n hits: Hit[];\n version: number;\n };\n return answer.texts;\n }\n\n async model(provider: string | undefined, request: OutgoingRequest): Promise<OutgoingRequest> {\n const fields = provider === undefined ? { request } : { provider, request };\n return ((await this.#call('model', fields)) as { request: OutgoingRequest }).request;\n }\n\n async mcp(server: string, request: OutgoingRequest): Promise<OutgoingRequest> {\n return ((await this.#call('mcp', { server, request })) as { request: OutgoingRequest }).request;\n }\n\n async records(): Promise<AgentRecord[]> {\n return ((await this.#call('records', {})) as { records: AgentRecord[] }).records;\n }\n\n async grant(\n server: string,\n response: string | Uint8Array,\n oauth: OAuthConfig,\n name?: string\n ): Promise<Granted> {\n const fields = { server, response, oauth, ...(name === undefined ? {} : { name }) };\n const { response: shown, records, expiresAt } = (await this.#call('grant', fields)) as Granted;\n return { response: shown, records, ...(expiresAt === undefined ? {} : { expiresAt }) };\n }\n\n async refresh(target: RefreshTarget, name?: string): Promise<string> {\n const fields = { ...target, ...(name === undefined ? {} : { name }) };\n return ((await this.#call('refresh', fields)) as { state: string }).state;\n }\n\n async endpoints(set: EndpointSet): Promise<void> {\n await this.#call('endpoints', { model: set.model, mcp: set.mcp });\n }\n\n stream(): ScrubStream {\n let stream: string | undefined;\n return {\n push: (chunk) => {\n if (stream === undefined && !this.needed) return Promise.resolve(chunk);\n if (stream === undefined) {\n stream = `${this.#tag}-${++this.#streamSerial}`;\n this.#streams.add(stream);\n void this.#call('redactStream', { stream });\n }\n return this.#call('push', { stream, chunk }).then(\n (answer) => (answer as { chunk: Uint8Array }).chunk\n );\n },\n end: async () => {\n if (stream === undefined) return EMPTY;\n const { chunk: tail } = (await this.#call('end', { stream })) as { chunk: Uint8Array };\n this.#streams.delete(stream);\n return tail;\n },\n drop: () => {\n if (stream === undefined) return;\n const dropped = stream;\n this.#streams.delete(dropped);\n for (const [id, item] of this.#pending)\n if (item.message.stream === dropped && item.message.op !== 'redactStream') {\n this.#pending.delete(id);\n item.resolve({ chunk: EMPTY });\n }\n void this.#call('drop', { stream: dropped });\n },\n };\n }\n\n #call(op: string, fields: Record<string, unknown>): Promise<unknown> {\n const message: Message = { v: 1, id: ++this.#serial, op, ...fields };\n const result = new Promise((resolve, reject) => {\n this.#pending.set(message.id, { message, at: this.#now(), resolve, reject });\n });\n this.#port?.postMessage(message);\n setTimeout(() => this.#refresh(), WAITING_MS);\n this.#refresh();\n return result;\n }\n\n #answer(data: Answer): void {\n if (!data || typeof data !== 'object') return;\n const pair = 'scrub' in data ? pairOf(data.scrub) : undefined;\n if (pair) this.#pair = pair;\n if (LOCKS.includes(data.locked)) this.#locked = data.locked as Locked;\n if (data.op === 'welcome') this.#welcome(data.status);\n const item = typeof data.id === 'number' ? this.#pending.get(data.id) : undefined;\n if (item) {\n this.#pending.delete(data.id as number);\n if (typeof data.version === 'number') this.#seen = Math.max(this.#seen, data.version);\n if (data.error)\n item.reject(new VaultRefusal(data.error.code, data.error.message ?? 'the vault refused'));\n else item.resolve(data);\n }\n this.#refresh();\n }\n\n #welcome(status: unknown): void {\n const given = status as { scrub?: unknown; locked?: unknown } | null;\n const pair = given && 'scrub' in given ? pairOf(given.scrub) : undefined;\n if (pair) this.#pair = pair;\n if (typeof given?.locked === 'boolean') this.#locked = given.locked ? 'passkey' : 'no';\n }\n\n #waiting(): boolean {\n const now = this.#now();\n return [...this.#pending.values()].some((item) => now - item.at >= WAITING_MS);\n }\n\n #holding(): boolean {\n return this.needed && (!this.#port || this.#waiting() || this.#locked === 'passkey');\n }\n\n #snapshot(): VaultState {\n return {\n port: !this.#port ? 'none' : this.#waiting() ? 'waiting' : 'ready',\n needed: this.needed,\n version: this.#pair.version,\n locked: this.#locked,\n held: this.#pending.size,\n };\n }\n\n #refresh(): void {\n const next = this.#snapshot();\n const before = this.state.value;\n if (Object.entries(next).some(([key, value]) => before[key as keyof VaultState] !== value))\n this.state.replace(BACKGROUND_CONTEXT, next);\n if (this.#holding()) return;\n for (const resolve of this.#waiters) resolve();\n this.#waiters.clear();\n }\n}\n\nexport function holdText(state: VaultState): string | undefined {\n const hold = vaultHold(state);\n if (!hold) return undefined;\n return hold.reason === 'locked' ? 'unlock the vault to continue' : WAITING;\n}\n\nexport function listenVault(\n scope: { addEventListener(type: 'message', listener: (event: MessageEvent) => void): void },\n vault: Vault\n): void {\n scope.addEventListener('message', ({ data }) => {\n const message = data as { vault?: MessagePort; scrub?: unknown; locked?: unknown } | null;\n if (!message || typeof message !== 'object') return;\n if (!('vault' in message || 'scrub' in message || 'locked' in message)) return;\n vault.connect(message.vault, message.scrub, message.locked);\n });\n}\n"],
|
|
5
|
+
"mappings": "AASA,SAAsC,uBAAuB;AAC7D,SAAS,0BAA0B;AAEnC,SAAS,iBAAiB;AAanB,MAAM,aAAa;AACnB,MAAM,UAAU;AAIhB,MAAM,qBAAqB,MAAM;AAAA,EAC7B;AAAA,EAET,YAAY,MAA6B,SAAiB;AACxD,UAAM,OAAO;AACb,SAAK,OAAO;AACZ,SAAK,OAAO;AAAA,EACd;AACF;AA8BA,MAAM,QAA4B,CAAC,MAAM,aAAa,SAAS;AAE/D,MAAM,QAAQ,IAAI,WAAW;AAE7B,SAAS,OAAO,OAAuC;AACrD,QAAM,OAAO;AACb,MAAI,SAAS,KAAM,QAAO,EAAE,QAAQ,OAAO,SAAS,EAAE;AACtD,MAAI,OAAO,MAAM,WAAW,aAAa,OAAO,KAAK,YAAY,SAAU,QAAO;AAClF,SAAO,EAAE,QAAQ,KAAK,QAAQ,SAAS,KAAK,QAAQ;AACtD;AAEO,MAAM,MAAuB;AAAA,EACzB;AAAA,EACA,WAAW,oBAAI,IAAqB;AAAA,EACpC,WAAW,oBAAI,IAAY;AAAA,EAC3B,WAAW,oBAAI,IAAgB;AAAA,EAC/B;AAAA,EACT;AAAA,EACA,QAAmB,EAAE,QAAQ,OAAO,SAAS,EAAE;AAAA,EAC/C,UAAkB;AAAA,EAClB,QAAQ;AAAA,EACR,UAAU;AAAA,EACV,gBAAgB;AAAA,EACP,OAAO,KAAK,OAAO,EAAE,SAAS,EAAE,EAAE,MAAM,GAAG,EAAE;AAAA,EAEtD,YAAY,MAAoB,KAAK,KAAK;AACxC,SAAK,OAAO;AACZ,SAAK,QAAQ,gBAA4B,KAAK,UAAU,CAAC;AAAA,EAC3D;AAAA,EAEA,IAAI,SAAkB;AACpB,WAAO,KAAK,MAAM,UAAU,KAAK,QAAQ,KAAK,MAAM;AAAA,EACtD;AAAA,EAEA,IAAI,YAAqB;AACvB,WAAO,KAAK,UAAU;AAAA,EACxB;AAAA,EAEA,QAAQ,MAA+B,OAAgB,QAAwB;AAC7E,UAAM,OAAO,UAAU,SAAY,SAAY,OAAO,KAAK;AAC3D,QAAI,KAAM,MAAK,QAAQ;AACvB,QAAI,OAAO,WAAW,UAAW,MAAK,UAAU,SAAS,YAAY;AACrE,QAAI,QAAQ,SAAS,KAAK,OAAO;AAC/B,UAAI,KAAK,MAAO,MAAK,MAAM,YAAY;AACvC,WAAK,QAAQ;AACb,WAAK,YAAY,CAAC,UAAU,KAAK,QAAQ,MAAM,IAAc;AAC7D,WAAK,QAAQ;AACb,YAAM,SAAS,CAAC,GAAG,KAAK,SAAS,OAAO,CAAC;AACzC,YAAM,UAAU,IAAI;AAAA,QAClB,OACG,OAAO,CAAC,SAAS,KAAK,QAAQ,OAAO,cAAc,EACnD,IAAI,CAAC,SAAS,KAAK,QAAQ,MAAM;AAAA,MACtC;AACA,iBAAW,UAAU,KAAK;AACxB,YAAI,CAAC,QAAQ,IAAI,MAAM,EAAG,MAAK,KAAK,MAAM,gBAAgB,EAAE,OAAO,CAAC;AACtE,iBAAW,QAAQ,OAAQ,MAAK,YAAY,KAAK,OAAO;AAAA,IAC1D;AACA,SAAK,SAAS;AAAA,EAChB;AAAA,EAEA,QAAuB;AACrB,QAAI,CAAC,KAAK,SAAS,EAAG,QAAO,QAAQ,QAAQ;AAC7C,WAAO,IAAI,QAAQ,CAAC,YAAY,KAAK,SAAS,IAAI,OAAO,CAAC;AAAA,EAC5D;AAAA,EAEA,MAAM,MAA4B,OAAmC;AACnE,QAAI,CAAC,KAAK,OAAQ,QAAO,CAAC,GAAG,KAAK;AAClC,UAAM,SAAU,MAAM,KAAK,MAAM,UAAU,EAAE,OAAO,CAAC,GAAG,KAAK,EAAE,CAAC;AAKhE,WAAO,OAAO;AAAA,EAChB;AAAA,EAEA,MAAM,MAAM,UAA8B,SAAoD;AAC5F,UAAM,SAAS,aAAa,SAAY,EAAE,QAAQ,IAAI,EAAE,UAAU,QAAQ;AAC1E,YAAS,MAAM,KAAK,MAAM,SAAS,MAAM,GAAoC;AAAA,EAC/E;AAAA,EAEA,MAAM,IAAI,QAAgB,SAAoD;AAC5E,YAAS,MAAM,KAAK,MAAM,OAAO,EAAE,QAAQ,QAAQ,CAAC,GAAoC;AAAA,EAC1F;AAAA,EAEA,MAAM,UAAkC;AACtC,YAAS,MAAM,KAAK,MAAM,WAAW,CAAC,CAAC,GAAkC;AAAA,EAC3E;AAAA,EAEA,MAAM,MACJ,QACA,UACA,OACA,MACkB;AAClB,UAAM,SAAS,EAAE,QAAQ,UAAU,OAAO,GAAI,SAAS,SAAY,CAAC,IAAI,EAAE,KAAK,EAAG;AAClF,UAAM,EAAE,UAAU,OAAO,SAAS,UAAU,IAAK,MAAM,KAAK,MAAM,SAAS,MAAM;AACjF,WAAO,EAAE,UAAU,OAAO,SAAS,GAAI,cAAc,SAAY,CAAC,IAAI,EAAE,UAAU,EAAG;AAAA,EACvF;AAAA,EAEA,MAAM,QAAQ,QAAuB,MAAgC;AACnE,UAAM,SAAS,EAAE,GAAG,QAAQ,GAAI,SAAS,SAAY,CAAC,IAAI,EAAE,KAAK,EAAG;AACpE,YAAS,MAAM,KAAK,MAAM,WAAW,MAAM,GAAyB;AAAA,EACtE;AAAA,EAEA,MAAM,UAAU,KAAiC;AAC/C,UAAM,KAAK,MAAM,aAAa,EAAE,OAAO,IAAI,OAAO,KAAK,IAAI,IAAI,CAAC;AAAA,EAClE;AAAA,EAEA,SAAsB;AACpB,QAAI;AACJ,WAAO;AAAA,MACL,MAAM,CAAC,UAAU;AACf,YAAI,WAAW,UAAa,CAAC,KAAK,OAAQ,QAAO,QAAQ,QAAQ,KAAK;AACtE,YAAI,WAAW,QAAW;AACxB,mBAAS,GAAG,KAAK,IAAI,IAAI,EAAE,KAAK,aAAa;AAC7C,eAAK,SAAS,IAAI,MAAM;AACxB,eAAK,KAAK,MAAM,gBAAgB,EAAE,OAAO,CAAC;AAAA,QAC5C;AACA,eAAO,KAAK,MAAM,QAAQ,EAAE,QAAQ,MAAM,CAAC,EAAE;AAAA,UAC3C,CAAC,WAAY,OAAiC;AAAA,QAChD;AAAA,MACF;AAAA,MACA,KAAK,YAAY;AACf,YAAI,WAAW,OAAW,QAAO;AACjC,cAAM,EAAE,OAAO,KAAK,IAAK,MAAM,KAAK,MAAM,OAAO,EAAE,OAAO,CAAC;AAC3D,aAAK,SAAS,OAAO,MAAM;AAC3B,eAAO;AAAA,MACT;AAAA,MACA,MAAM,MAAM;AACV,YAAI,WAAW,OAAW;AAC1B,cAAM,UAAU;AAChB,aAAK,SAAS,OAAO,OAAO;AAC5B,mBAAW,CAAC,IAAI,IAAI,KAAK,KAAK;AAC5B,cAAI,KAAK,QAAQ,WAAW,WAAW,KAAK,QAAQ,OAAO,gBAAgB;AACzE,iBAAK,SAAS,OAAO,EAAE;AACvB,iBAAK,QAAQ,EAAE,OAAO,MAAM,CAAC;AAAA,UAC/B;AACF,aAAK,KAAK,MAAM,QAAQ,EAAE,QAAQ,QAAQ,CAAC;AAAA,MAC7C;AAAA,IACF;AAAA,EACF;AAAA,EAEA,MAAM,IAAY,QAAmD;AACnE,UAAM,UAAmB,EAAE,GAAG,GAAG,IAAI,EAAE,KAAK,SAAS,IAAI,GAAG,OAAO;AACnE,UAAM,SAAS,IAAI,QAAQ,CAAC,SAAS,WAAW;AAC9C,WAAK,SAAS,IAAI,QAAQ,IAAI,EAAE,SAAS,IAAI,KAAK,KAAK,GAAG,SAAS,OAAO,CAAC;AAAA,IAC7E,CAAC;AACD,SAAK,OAAO,YAAY,OAAO;AAC/B,eAAW,MAAM,KAAK,SAAS,GAAG,UAAU;AAC5C,SAAK,SAAS;AACd,WAAO;AAAA,EACT;AAAA,EAEA,QAAQ,MAAoB;AAC1B,QAAI,CAAC,QAAQ,OAAO,SAAS,SAAU;AACvC,UAAM,OAAO,WAAW,OAAO,OAAO,KAAK,KAAK,IAAI;AACpD,QAAI,KAAM,MAAK,QAAQ;AACvB,QAAI,MAAM,SAAS,KAAK,MAAM,EAAG,MAAK,UAAU,KAAK;AACrD,QAAI,KAAK,OAAO,UAAW,MAAK,SAAS,KAAK,MAAM;AACpD,UAAM,OAAO,OAAO,KAAK,OAAO,WAAW,KAAK,SAAS,IAAI,KAAK,EAAE,IAAI;AACxE,QAAI,MAAM;AACR,WAAK,SAAS,OAAO,KAAK,EAAY;AACtC,UAAI,OAAO,KAAK,YAAY,SAAU,MAAK,QAAQ,KAAK,IAAI,KAAK,OAAO,KAAK,OAAO;AACpF,UAAI,KAAK;AACP,aAAK,OAAO,IAAI,aAAa,KAAK,MAAM,MAAM,KAAK,MAAM,WAAW,mBAAmB,CAAC;AAAA,UACrF,MAAK,QAAQ,IAAI;AAAA,IACxB;AACA,SAAK,SAAS;AAAA,EAChB;AAAA,EAEA,SAAS,QAAuB;AAC9B,UAAM,QAAQ;AACd,UAAM,OAAO,SAAS,WAAW,QAAQ,OAAO,MAAM,KAAK,IAAI;AAC/D,QAAI,KAAM,MAAK,QAAQ;AACvB,QAAI,OAAO,OAAO,WAAW,UAAW,MAAK,UAAU,MAAM,SAAS,YAAY;AAAA,EACpF;AAAA,EAEA,WAAoB;AAClB,UAAM,MAAM,KAAK,KAAK;AACtB,WAAO,CAAC,GAAG,KAAK,SAAS,OAAO,CAAC,EAAE,KAAK,CAAC,SAAS,MAAM,KAAK,MAAM,UAAU;AAAA,EAC/E;AAAA,EAEA,WAAoB;AAClB,WAAO,KAAK,WAAW,CAAC,KAAK,SAAS,KAAK,SAAS,KAAK,KAAK,YAAY;AAAA,EAC5E;AAAA,EAEA,YAAwB;AACtB,WAAO;AAAA,MACL,MAAM,CAAC,KAAK,QAAQ,SAAS,KAAK,SAAS,IAAI,YAAY;AAAA,MAC3D,QAAQ,KAAK;AAAA,MACb,SAAS,KAAK,MAAM;AAAA,MACpB,QAAQ,KAAK;AAAA,MACb,MAAM,KAAK,SAAS;AAAA,IACtB;AAAA,EACF;AAAA,EAEA,WAAiB;AACf,UAAM,OAAO,KAAK,UAAU;AAC5B,UAAM,SAAS,KAAK,MAAM;AAC1B,QAAI,OAAO,QAAQ,IAAI,EAAE,KAAK,CAAC,CAAC,KAAK,KAAK,MAAM,OAAO,GAAuB,MAAM,KAAK;AACvF,WAAK,MAAM,QAAQ,oBAAoB,IAAI;AAC7C,QAAI,KAAK,SAAS,EAAG;AACrB,eAAW,WAAW,KAAK,SAAU,SAAQ;AAC7C,SAAK,SAAS,MAAM;AAAA,EACtB;AACF;AAEO,SAAS,SAAS,OAAuC;AAC9D,QAAM,OAAO,UAAU,KAAK;AAC5B,MAAI,CAAC,KAAM,QAAO;AAClB,SAAO,KAAK,WAAW,WAAW,iCAAiC;AACrE;AAEO,SAAS,YACd,OACA,OACM;AACN,QAAM,iBAAiB,WAAW,CAAC,EAAE,KAAK,MAAM;AAC9C,UAAM,UAAU;AAChB,QAAI,CAAC,WAAW,OAAO,YAAY,SAAU;AAC7C,QAAI,EAAE,WAAW,WAAW,WAAW,WAAW,YAAY,SAAU;AACxE,UAAM,QAAQ,QAAQ,OAAO,QAAQ,OAAO,QAAQ,MAAM;AAAA,EAC5D,CAAC;AACH;",
|
|
6
6
|
"names": []
|
|
7
7
|
}
|
package/dist/services.js.map
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"version": 3,
|
|
3
3
|
"sources": ["../src/services.ts"],
|
|
4
|
-
"sourcesContent": ["import {\n type Context,\n defineService,\n type JsonValue,\n type ReplicatedState,\n} from '@earendil-works/chord';\nimport type { ConversationView } from '@earendil-works/pi-durable';\nimport type { SendAttachment, ShownAttachment } from './attachments.ts';\nimport type { ChangesView } from './changes/git.ts';\nimport type { FrozenCone } from './freezer/index.ts';\nimport type { MemoryEntry, MemoryScope, MemoryTag } from './memory/format.ts';\nimport type { AgentRemote } from './remote/host.ts';\nimport type { AgentPages } from './remote/pages.ts';\nimport type { VaultState } from './secrets/vault.ts';\nimport type { Sprinkle } from './sprinkles/kind.ts';\n\nexport type SendMode = 'steer' | 'followUp' | 'reject';\n\nexport interface SendRequest {\n text: string;\n whenBusy: SendMode;\n requestId: string | null;\n agentId?: string | null;\n attachments?: SendAttachment[];\n}\n\nexport interface OperationError {\n code: string;\n message: string;\n}\n\nexport type SendResponse =\n | { accepted: true; submissionId: string; error: null }\n | { accepted: false; submissionId: null; error: OperationError };\n\nexport type PromptResult =\n | { status: 'done'; text: string; reason: null }\n | { status: 'unanswered'; text: null; reason: string };\n\nexport interface AgentControl {\n send(request: SendRequest, context: Context): Promise<SendResponse>;\n wait(submissionId: string, context: Context): Promise<PromptResult>;\n withdraw(\n submissionId: string,\n context: Context\n ): Promise<{ outcome: 'withdrawn' | 'already_placed' | 'not_found' }>;\n abort(context: Context): Promise<void>;\n compact(instructions: string | null, context: Context): Promise<SendResponse>;\n compactAgent(\n agentId: string,\n instructions: string | null,\n context: Context\n ): Promise<SendResponse>;\n reset(handoff: string | null, context: Context): Promise<void>;\n configure(change: AgentSettingsChange, context: Context): Promise<void>;\n rewind(messageId: string | null, context: Context): Promise<Rewound>;\n rewindAgent(agentId: string, messageId: string | null, context: Context): Promise<Rewound>;\n resolveLick(\n lickId: string,\n state: 'confirmed' | 'dismissed',\n context: Context\n ): Promise<LickResolved>;\n resolveAgentLick(\n agentId: string,\n lickId: string,\n state: 'confirmed' | 'dismissed',\n context: Context\n ): Promise<LickResolved>;\n webhook(\n name: string,\n delivery: WebhookRequest,\n context: Context\n ): Promise<{ delivered: boolean }>;\n stopAgent(agentId: string, context: Context): Promise<void>;\n selectCone(agentId: string, context: Context): Promise<void>;\n createCone(name: string, context: Context): Promise<Created>;\n createScoop(parentId: string, name: string, context: Context): Promise<Created>;\n drop(agentId: string, context: Context): Promise<Created>;\n unqueue(\n agentId: string | null,\n submissionId: string,\n context: Context\n ): Promise<{ outcome: 'withdrawn' | 'already_placed' | 'not_found' }>;\n sprinkleSend(\n sprinkleId: string,\n payload: { action: string; data: JsonValue | null; target: string | null },\n context: Context\n ): Promise<{ delivered: boolean }>;\n sprinkleCall(\n sprinkleId: string,\n method: string,\n args: JsonValue[],\n context: Context\n ): Promise<JsonValue>;\n memorySave(draft: MemoryDraft, context: Context): Promise<MemoryEntry>;\n memoryRemove(id: string, context: Context): Promise<{ removed: boolean }>;\n freeze(agentId: string, context: Context): Promise<Created>;\n newChat(agentId: string, context: Context): Promise<Created>;\n thaw(frozenId: string, context: Context): Promise<Created>;\n discard(frozenId: string, context: Context): Promise<Created>;\n changesOpen(context: Context): Promise<void>;\n changeAccept(path: string, context: Context): Promise<Created>;\n changeRevert(path: string, context: Context): Promise<Created>;\n monitorOpen(lease: string | null, resync: boolean, context: Context): Promise<MonitorLease>;\n monitorClose(lease: string, context: Context): Promise<void>;\n image(ref: ImageRef, context: Context): Promise<StoredImage>;\n}\n\nexport interface ImageRef {\n entry: number;\n message: number;\n part: number;\n}\n\nexport type StoredImage = { data: string; mimeType: string } | { data: null; mimeType: null };\n\nexport interface MonitorLease {\n lease: string;\n ttlMs: number;\n}\n\nexport interface MonitorAgent {\n id: string;\n name: string;\n kind: 'cone' | 'scoop';\n parentId: string | null;\n model: string | null;\n running: boolean;\n queued: number;\n tool: string | null;\n retry: { attempt: number; since: number; error: string } | null;\n failed: string | null;\n context: number | null;\n cpu?: number | null;\n}\n\nexport interface MonitorTask {\n id: string;\n kind: string;\n detail: string | null;\n agentId: string | null;\n owner: string | null;\n status: 'pending' | 'running' | 'waiting' | 'completing';\n phase: string;\n background: boolean;\n aborting: number | null;\n since: number;\n waits: number;\n}\n\nexport interface MonitorProcess {\n pid: number;\n ppid: number;\n pgid: number;\n user: string | null;\n agentId: string | null;\n command: string;\n state: 'S' | 'Z';\n started: number;\n zombie: number | null;\n tty: boolean;\n rss: number | null;\n utime?: number;\n stime?: number;\n cpu?: number | null;\n}\n\nexport interface MonitorProblem {\n id: string;\n at: number;\n agentId: string | null;\n kind: 'task' | 'retry' | 'turn';\n message: string;\n}\n\nexport interface MonitorFeed {\n open: boolean;\n at: number;\n usage: { tokens: number; cost: number; free: boolean } | null;\n agents: MonitorAgent[];\n tasks: MonitorTask[];\n processes: MonitorProcess[] | null;\n kernel: 'checking' | 'ok' | 'unreachable';\n problems: MonitorProblem[];\n paused: boolean;\n}\n\nexport interface MemoryDraft {\n id: string | null;\n scope: string;\n section: string;\n title: string;\n body: string;\n tag: MemoryTag | null;\n}\n\nexport type Created = { id: string; error: null } | { id: null; error: string };\n\nexport interface AgentSummary {\n id: string;\n name: string;\n kind: 'cone' | 'scoop';\n parentId: string | null;\n role: string | null;\n}\n\nexport interface AgentsSummary {\n active: string;\n agents: AgentSummary[];\n}\n\nexport type LickResolved =\n | { done: true; text: string; error: null }\n | { done: false; text: null; error: string };\n\nexport interface WebhookRequest {\n id: string | null;\n headers: Record<string, string>;\n body: string;\n}\n\nexport type Rewound =\n | { done: true; text: string; reason: null; attachments?: ShownAttachment[] }\n | { done: false; text: null; reason: 'busy' | 'no-turn' };\n\nexport interface AgentSettingsChange {\n model: { provider: string; modelId: string } | null;\n thinkingLevel: 'off' | 'minimal' | 'low' | 'medium' | 'high' | 'xhigh' | 'max' | null;\n agentId?: string | null;\n}\n\nexport const AgentControl = defineService<AgentControl>('slicc.agent.control');\n\nexport type Delivered = 'run' | 'steer' | 'follow-up';\n\nexport interface AgentTranscript {\n readonly state: ReplicatedState<ConversationView>;\n readonly deliveries: ReplicatedState<Record<string, Delivered>>;\n readonly agents: ReplicatedState<AgentsSummary>;\n readonly views: ReplicatedState<Record<string, ConversationView>>;\n readonly commands: ReplicatedState<Command[]>;\n readonly sprinkles: ReplicatedState<Sprinkle[]>;\n readonly memories: ReplicatedState<MemoryEntry[]>;\n readonly memoryScopes: ReplicatedState<MemoryScope[]>;\n readonly frozen: ReplicatedState<FrozenCone[]>;\n readonly changes: ReplicatedState<ChangesView>;\n readonly monitor: ReplicatedState<MonitorFeed>;\n readonly vault: ReplicatedState<VaultState>;\n}\n\nexport interface Command {\n name: string;\n description: string;\n kind: 'prompt' | 'skill' | 'action';\n}\n\nexport const AgentTranscript = defineService<AgentTranscript>('slicc.agent.transcript');\n\nexport interface AgentSessions {\n attach(sessionId: string, context: Context): Promise<void>;\n detach(context: Context): Promise<void>;\n}\n\nexport const AgentSessions = defineService<AgentSessions>('slicc.agent.sessions');\n\nexport const AgentRemoteService = defineService<AgentRemote>('slicc.agent.remote');\n\nexport const AgentPagesService = defineService<AgentPages>('slicc.agent.pages');\n\nexport const AGENT_SESSION = 'agent';\n\nexport interface ModelChoice {\n id: string;\n label: string;\n provider: string;\n kind: 'chat' | 'classifier';\n reasoning: boolean;\n images?: boolean;\n contextWindow: number;\n}\n\nexport interface AccountState {\n id: string;\n provider: string;\n identity: string;\n status: 'connected' | 'disconnected' | 'expired';\n auth: 'api-key' | 'oauth';\n needs: 'cors-free-transport' | null;\n group?: 'providers' | 'mcp';\n secret?: 'api-key' | 'token';\n}\n\nexport interface BudgetState {\n provider: string;\n percent: number;\n window: 'weekly';\n resets: string;\n}\n\nexport interface SignIn {\n clientId: string;\n scopes: string;\n imsEnvironment: string;\n}\n\nexport interface McpSignIn {\n url: string;\n state: string;\n}\n\nexport interface SettingsState {\n models: ModelChoice[];\n accounts: AccountState[];\n budget?: BudgetState | null;\n}\n\nexport interface AgentSettings {\n readonly state: ReplicatedState<SettingsState>;\n connect(\n providerId: string,\n secret: string,\n region: string | null,\n context: Context\n ): Promise<void>;\n disconnect(providerId: string, context: Context): Promise<void>;\n signIn(providerId: string, context: Context): Promise<SignIn | McpSignIn | null>;\n}\n\nexport const AgentSettings = defineService<AgentSettings>('slicc.agent.settings');\n"],
|
|
5
|
-
"mappings": "AAAA;AAAA,EAEE;AAAA,OAGK;AAkOA,MAAM,eAAe,cAA4B,qBAAqB;AAyBtE,MAAM,kBAAkB,cAA+B,wBAAwB;AAO/E,MAAM,gBAAgB,cAA6B,sBAAsB;AAEzE,MAAM,qBAAqB,cAA2B,oBAAoB;AAE1E,MAAM,oBAAoB,cAA0B,mBAAmB;AAEvE,MAAM,gBAAgB;
|
|
4
|
+
"sourcesContent": ["import {\n type Context,\n defineService,\n type JsonValue,\n type ReplicatedState,\n} from '@earendil-works/chord';\nimport type { ConversationView } from '@earendil-works/pi-durable';\nimport type { SendAttachment, ShownAttachment } from './attachments.ts';\nimport type { ChangesView } from './changes/git.ts';\nimport type { FrozenCone } from './freezer/index.ts';\nimport type { MemoryEntry, MemoryScope, MemoryTag } from './memory/format.ts';\nimport type { AgentRemote } from './remote/host.ts';\nimport type { AgentPages } from './remote/pages.ts';\nimport type { VaultState } from './secrets/vault.ts';\nimport type { Sprinkle } from './sprinkles/kind.ts';\n\nexport type SendMode = 'steer' | 'followUp' | 'reject';\n\nexport interface SendRequest {\n text: string;\n whenBusy: SendMode;\n requestId: string | null;\n agentId?: string | null;\n attachments?: SendAttachment[];\n}\n\nexport interface OperationError {\n code: string;\n message: string;\n}\n\nexport type SendResponse =\n | { accepted: true; submissionId: string; error: null }\n | { accepted: false; submissionId: null; error: OperationError };\n\nexport type PromptResult =\n | { status: 'done'; text: string; reason: null }\n | { status: 'unanswered'; text: null; reason: string };\n\nexport interface AgentControl {\n send(request: SendRequest, context: Context): Promise<SendResponse>;\n wait(submissionId: string, context: Context): Promise<PromptResult>;\n withdraw(\n submissionId: string,\n context: Context\n ): Promise<{ outcome: 'withdrawn' | 'already_placed' | 'not_found' }>;\n abort(context: Context): Promise<void>;\n compact(instructions: string | null, context: Context): Promise<SendResponse>;\n compactAgent(\n agentId: string,\n instructions: string | null,\n context: Context\n ): Promise<SendResponse>;\n reset(handoff: string | null, context: Context): Promise<void>;\n configure(change: AgentSettingsChange, context: Context): Promise<void>;\n rewind(messageId: string | null, context: Context): Promise<Rewound>;\n rewindAgent(agentId: string, messageId: string | null, context: Context): Promise<Rewound>;\n resolveLick(\n lickId: string,\n state: 'confirmed' | 'dismissed',\n context: Context\n ): Promise<LickResolved>;\n resolveAgentLick(\n agentId: string,\n lickId: string,\n state: 'confirmed' | 'dismissed',\n context: Context\n ): Promise<LickResolved>;\n webhook(\n name: string,\n delivery: WebhookRequest,\n context: Context\n ): Promise<{ delivered: boolean }>;\n stopAgent(agentId: string, context: Context): Promise<void>;\n selectCone(agentId: string, context: Context): Promise<void>;\n createCone(name: string, context: Context): Promise<Created>;\n createScoop(parentId: string, name: string, context: Context): Promise<Created>;\n drop(agentId: string, context: Context): Promise<Created>;\n unqueue(\n agentId: string | null,\n submissionId: string,\n context: Context\n ): Promise<{ outcome: 'withdrawn' | 'already_placed' | 'not_found' }>;\n sprinkleSend(\n sprinkleId: string,\n payload: { action: string; data: JsonValue | null; target: string | null },\n context: Context\n ): Promise<{ delivered: boolean }>;\n sprinkleCall(\n sprinkleId: string,\n method: string,\n args: JsonValue[],\n context: Context\n ): Promise<JsonValue>;\n memorySave(draft: MemoryDraft, context: Context): Promise<MemoryEntry>;\n memoryRemove(id: string, context: Context): Promise<{ removed: boolean }>;\n freeze(agentId: string, context: Context): Promise<Created>;\n newChat(agentId: string, context: Context): Promise<Created>;\n thaw(frozenId: string, context: Context): Promise<Created>;\n discard(frozenId: string, context: Context): Promise<Created>;\n changesOpen(context: Context): Promise<void>;\n changeAccept(path: string, context: Context): Promise<Created>;\n changeRevert(path: string, context: Context): Promise<Created>;\n monitorOpen(lease: string | null, resync: boolean, context: Context): Promise<MonitorLease>;\n monitorClose(lease: string, context: Context): Promise<void>;\n image(ref: ImageRef, context: Context): Promise<StoredImage>;\n}\n\nexport interface ImageRef {\n entry: number;\n message: number;\n part: number;\n}\n\nexport type StoredImage = { data: string; mimeType: string } | { data: null; mimeType: null };\n\nexport interface MonitorLease {\n lease: string;\n ttlMs: number;\n}\n\nexport interface MonitorAgent {\n id: string;\n name: string;\n kind: 'cone' | 'scoop';\n parentId: string | null;\n model: string | null;\n running: boolean;\n queued: number;\n tool: string | null;\n retry: { attempt: number; since: number; error: string } | null;\n failed: string | null;\n context: number | null;\n cpu?: number | null;\n}\n\nexport interface MonitorTask {\n id: string;\n kind: string;\n detail: string | null;\n agentId: string | null;\n owner: string | null;\n status: 'pending' | 'running' | 'waiting' | 'completing';\n phase: string;\n background: boolean;\n aborting: number | null;\n since: number;\n waits: number;\n}\n\nexport interface MonitorProcess {\n pid: number;\n ppid: number;\n pgid: number;\n user: string | null;\n agentId: string | null;\n command: string;\n state: 'S' | 'Z';\n started: number;\n zombie: number | null;\n tty: boolean;\n rss: number | null;\n utime?: number;\n stime?: number;\n cpu?: number | null;\n}\n\nexport interface MonitorProblem {\n id: string;\n at: number;\n agentId: string | null;\n kind: 'task' | 'retry' | 'turn';\n message: string;\n}\n\nexport interface MonitorFeed {\n open: boolean;\n at: number;\n usage: { tokens: number; cost: number; free: boolean } | null;\n agents: MonitorAgent[];\n tasks: MonitorTask[];\n processes: MonitorProcess[] | null;\n kernel: 'checking' | 'ok' | 'unreachable';\n problems: MonitorProblem[];\n paused: boolean;\n}\n\nexport interface MemoryDraft {\n id: string | null;\n scope: string;\n section: string;\n title: string;\n body: string;\n tag: MemoryTag | null;\n}\n\nexport type Created = { id: string; error: null } | { id: null; error: string };\n\nexport interface AgentSummary {\n id: string;\n name: string;\n kind: 'cone' | 'scoop';\n parentId: string | null;\n role: string | null;\n}\n\nexport interface AgentsSummary {\n active: string;\n agents: AgentSummary[];\n}\n\nexport type LickResolved =\n | { done: true; text: string; error: null }\n | { done: false; text: null; error: string };\n\nexport interface WebhookRequest {\n id: string | null;\n headers: Record<string, string>;\n body: string;\n}\n\nexport type Rewound =\n | { done: true; text: string; reason: null; attachments?: ShownAttachment[] }\n | { done: false; text: null; reason: 'busy' | 'no-turn' };\n\nexport interface AgentSettingsChange {\n model: { provider: string; modelId: string } | null;\n thinkingLevel: 'off' | 'minimal' | 'low' | 'medium' | 'high' | 'xhigh' | 'max' | null;\n agentId?: string | null;\n}\n\nexport const AgentControl = defineService<AgentControl>('slicc.agent.control');\n\nexport type Delivered = 'run' | 'steer' | 'follow-up';\n\nexport interface AgentTranscript {\n readonly state: ReplicatedState<ConversationView>;\n readonly deliveries: ReplicatedState<Record<string, Delivered>>;\n readonly agents: ReplicatedState<AgentsSummary>;\n readonly views: ReplicatedState<Record<string, ConversationView>>;\n readonly commands: ReplicatedState<Command[]>;\n readonly sprinkles: ReplicatedState<Sprinkle[]>;\n readonly memories: ReplicatedState<MemoryEntry[]>;\n readonly memoryScopes: ReplicatedState<MemoryScope[]>;\n readonly frozen: ReplicatedState<FrozenCone[]>;\n readonly changes: ReplicatedState<ChangesView>;\n readonly monitor: ReplicatedState<MonitorFeed>;\n readonly vault: ReplicatedState<VaultState>;\n}\n\nexport interface Command {\n name: string;\n description: string;\n kind: 'prompt' | 'skill' | 'action';\n}\n\nexport const AgentTranscript = defineService<AgentTranscript>('slicc.agent.transcript');\n\nexport interface AgentSessions {\n attach(sessionId: string, context: Context): Promise<void>;\n detach(context: Context): Promise<void>;\n}\n\nexport const AgentSessions = defineService<AgentSessions>('slicc.agent.sessions');\n\nexport const AgentRemoteService = defineService<AgentRemote>('slicc.agent.remote');\n\nexport const AgentPagesService = defineService<AgentPages>('slicc.agent.pages');\n\nexport const AGENT_SESSION = 'agent';\n\nexport interface ModelChoice {\n id: string;\n label: string;\n provider: string;\n kind: 'chat' | 'classifier';\n reasoning: boolean;\n images?: boolean;\n contextWindow: number;\n}\n\nexport interface AccountState {\n id: string;\n provider: string;\n identity: string;\n status: 'connected' | 'disconnected' | 'expired';\n auth: 'api-key' | 'oauth';\n needs: 'cors-free-transport' | null;\n group?: 'providers' | 'mcp';\n secret?: 'api-key' | 'token';\n store?: 'vault';\n fields?: AccountField[];\n}\n\nexport interface AccountField {\n name: string;\n label: string;\n required?: boolean;\n}\n\nexport interface BudgetState {\n provider: string;\n percent: number;\n window: 'weekly';\n resets: string;\n}\n\nexport interface SignIn {\n clientId: string;\n scopes: string;\n imsEnvironment: string;\n}\n\nexport interface McpSignIn {\n url: string;\n state: string;\n}\n\nexport interface SettingsState {\n models: ModelChoice[];\n accounts: AccountState[];\n budget?: BudgetState | null;\n}\n\nexport interface AgentSettings {\n readonly state: ReplicatedState<SettingsState>;\n connect(\n providerId: string,\n secret: string | null,\n fields: Record<string, string> | null,\n context: Context\n ): Promise<void>;\n disconnect(providerId: string, context: Context): Promise<void>;\n signIn(providerId: string, context: Context): Promise<SignIn | McpSignIn | null>;\n}\n\nexport const AgentSettings = defineService<AgentSettings>('slicc.agent.settings');\n"],
|
|
5
|
+
"mappings": "AAAA;AAAA,EAEE;AAAA,OAGK;AAkOA,MAAM,eAAe,cAA4B,qBAAqB;AAyBtE,MAAM,kBAAkB,cAA+B,wBAAwB;AAO/E,MAAM,gBAAgB,cAA6B,sBAAsB;AAEzE,MAAM,qBAAqB,cAA2B,oBAAoB;AAE1E,MAAM,oBAAoB,cAA0B,mBAAmB;AAEvE,MAAM,gBAAgB;AAmEtB,MAAM,gBAAgB,cAA6B,sBAAsB;",
|
|
6
6
|
"names": []
|
|
7
7
|
}
|