@agentproto/runtime 3.6.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 +7 -3
- package/dist/app-ui-delivery.d.ts +75 -0
- package/dist/app-ui-delivery.mjs +144 -0
- package/dist/app-ui-delivery.mjs.map +1 -0
- package/dist/catalog-models.d.ts +5 -3
- package/dist/catalog-models.mjs.map +1 -1
- package/dist/config-schema.d.ts +134 -0
- package/dist/config-schema.mjs +3687 -0
- package/dist/config-schema.mjs.map +1 -0
- package/dist/config.d.ts +10 -2
- package/dist/config.mjs +3605 -4
- package/dist/config.mjs.map +1 -1
- package/dist/{context-continuity-ib9_bVYM.d.ts → context-continuity-Bn99UtVC.d.ts} +40 -1
- package/dist/{heartbeat-COGpMrJS.d.ts → heartbeat-BJtxbDb9.d.ts} +13 -1
- package/dist/heartbeat.d.ts +1 -1
- package/dist/index.d.ts +2194 -118
- package/dist/index.mjs +15283 -7041
- package/dist/index.mjs.map +1 -1
- package/dist/mcp-imports.d.ts +2 -1
- package/dist/resume-strategies.mjs +20 -1
- package/dist/resume-strategies.mjs.map +1 -1
- package/dist/{session-config-DbWP9RRj.d.ts → session-config-ByfVeEQJ.d.ts} +1 -1
- package/dist/session-presence.mjs +3603 -6
- package/dist/session-presence.mjs.map +1 -1
- package/dist/session-story.d.ts +10 -0
- package/dist/{spawn-defaults-CwI9Puwy.d.ts → spawn-defaults-CZj39Znq.d.ts} +146 -2
- package/dist/user-presets.d.ts +8 -2
- package/dist/user-presets.mjs +2 -1
- package/dist/user-presets.mjs.map +1 -1
- package/package.json +36 -23
package/README.md
CHANGED
|
@@ -66,16 +66,20 @@ The `/mcp` endpoint exposes the core toolset plus several opt-in / feature-gated
|
|
|
66
66
|
| `session_list` / `session_tree` / `session_usage` / `session_restart` / `session_rename` | Session management |
|
|
67
67
|
| `app_install` / `app_run` / `app_list` / `app_status` / `app_stop` / `app_apply` / `app_unapply` / `app_list_applied` | App-kit apps |
|
|
68
68
|
| `app_data_read` / `app_data_write` / `app_data_list` / `app_data_migrate` | App-scoped durable data plane, anchored at the app's `dataDir` (default `<dir>/data`; `app_install {dataDir}`) |
|
|
69
|
-
| `app_state_append` / `app_state_get` / `app_state_list` | App-scoped **state ledger** (`<
|
|
69
|
+
| `app_state_append` / `app_state_get` / `app_state_list` | App-scoped **state ledger** (`<stateDir>/events.jsonl`, under `~/.agentproto/app-state/`) — append-only, zod-validated event envelope, fold to a stage snapshot; see below |
|
|
70
70
|
| `harness_preset_list` / `harness_preset_create` / `harness_preset_delete` / `harness_preset_set_default` | Persisted harness→auth-profile presets (new) |
|
|
71
|
+
| `review_run` / `review_status` / `review_cancel` / `review_ledger` / `review_export` | [`@agentproto/review`](../review) host: run a REVIEW.md binding over a git range (command lanes as subprocesses, agent lanes as child reviewer sessions), fold a `pass`/`block`/`incomplete` verdict, and record the attestation in the review ledger (`~/.agentproto/reviews`) (new) |
|
|
71
72
|
| `workspace_brain_query` / `workspace_brain_status` / `workspace_brain_ingest` | Per-workspace transcript recall (new) |
|
|
72
73
|
| `conversation_export` | Export a daemon transcript to a target adapter's native store, e.g. `claude-code` (new) |
|
|
73
74
|
| `llm_endpoint_*` (`start`, `stop`, `status`, `set_upstream_link`, `list_links`) | Local LLM Endpoint proxy sidecar — only when `features.llmEndpoint` is enabled (new) |
|
|
74
75
|
|
|
75
76
|
### App state ledger (`app_state_*`)
|
|
76
77
|
|
|
77
|
-
Per installed app, an append-only JSONL event log lives
|
|
78
|
-
|
|
78
|
+
Per installed app, an append-only JSONL event log lives in the daemon's own
|
|
79
|
+
state dir, `~/.agentproto/app-state/<encoded appId>/events.jsonl`
|
|
80
|
+
(`InstalledApp.stateDir`, `src/app-state.ts`) — never in the app's source
|
|
81
|
+
tree. A ledger left at the old `<dataDir>/state/events.jsonl` is still read,
|
|
82
|
+
and moved over on the next append. One JSON object per
|
|
79
83
|
line: `{ id (ULID), ts, appRunId?, stage, item?, kind, by, payload }` with
|
|
80
84
|
`kind ∈ stage-started | gate-report | approval | stage-done | blocked | note`
|
|
81
85
|
and `by ∈ runner | human | policy | system`. Payloads are validated per kind
|
|
@@ -0,0 +1,75 @@
|
|
|
1
|
+
import { IncomingMessage, ServerResponse } from 'node:http';
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* HTTP delivery primitives for the app-UI shell — `GET /apps/:appId/ui` and
|
|
5
|
+
* `GET /apps/:appId/ui/assets/:file` on the daemon (http-server.ts), and the
|
|
6
|
+
* same shapes under `agentproto app serve` (cli/src/app-serve.ts). One
|
|
7
|
+
* module so both hosts negotiate, validate and cache identically:
|
|
8
|
+
*
|
|
9
|
+
* - `accept-encoding` negotiation (`br` preferred, then `gzip`, else
|
|
10
|
+
* identity) with `vary: accept-encoding` on every response.
|
|
11
|
+
* - A strong `etag` (sha256 of the exact bytes served) answered with 304
|
|
12
|
+
* on a matching `if-none-match`.
|
|
13
|
+
* - An LRU of encoded representations keyed by a caller-chosen key and
|
|
14
|
+
* invalidated by a caller-chosen stamp (path + mtime + size for files),
|
|
15
|
+
* so neither the digest nor the compression reruns until the file
|
|
16
|
+
* changes.
|
|
17
|
+
*
|
|
18
|
+
* Deliberately scoped to the shell: SSE, MCP and every API route keep their
|
|
19
|
+
* own framing and never go through here.
|
|
20
|
+
*/
|
|
21
|
+
|
|
22
|
+
type ContentCoding = "br" | "gzip" | "identity";
|
|
23
|
+
/** Pick the response coding from an `accept-encoding` header: `br` when
|
|
24
|
+
* acceptable, then `gzip`, else identity. q-values are honoured only as
|
|
25
|
+
* acceptable (`q>0`) vs refused (`q=0`) — the preference order is ours, not
|
|
26
|
+
* the client's. A `*` entry covers codings the header doesn't name. */
|
|
27
|
+
declare function negotiateContentEncoding(header: string | string[] | undefined): ContentCoding;
|
|
28
|
+
/** Strong entity tag over `body` (sha256, base64url). `variant`, when set,
|
|
29
|
+
* is appended so two representations of the same bytes that carry
|
|
30
|
+
* different response headers (e.g. with/without frame headers) never
|
|
31
|
+
* validate each other's cache entry. */
|
|
32
|
+
declare function strongEtag(body: Buffer | string, variant?: string): string;
|
|
33
|
+
/** `if-none-match` evaluation (RFC 9110 §13.1.2): `*` or any listed tag
|
|
34
|
+
* equal to `etag` under weak comparison. */
|
|
35
|
+
declare function ifNoneMatchHits(header: string | string[] | undefined, etag: string): boolean;
|
|
36
|
+
/** Content types the app-UI routes serve, by lowercase extension. */
|
|
37
|
+
declare const APP_UI_MIME_BY_EXT: Readonly<Record<string, string>>;
|
|
38
|
+
/** Content type for an extension (with or without the leading dot). */
|
|
39
|
+
declare function appUiContentType(ext: string): string;
|
|
40
|
+
/** Whether a content type is worth compressing — text-ish only; woff2/png
|
|
41
|
+
* and friends are already compressed. */
|
|
42
|
+
declare function isCompressibleContentType(contentType: string): boolean;
|
|
43
|
+
/** `:file` segment of the assets route: a flat name from `[A-Za-z0-9._-]`,
|
|
44
|
+
* not starting with `.` (so no `.`/`..`, no dotfiles), no separators. */
|
|
45
|
+
declare function isValidAppUiAssetName(file: string): boolean;
|
|
46
|
+
/** Assets route cache policy — Vite emits content-hashed file names. */
|
|
47
|
+
declare const IMMUTABLE_CACHE_CONTROL = "public, max-age=31536000, immutable";
|
|
48
|
+
/** One servable body, its strong etag, and its encodings (computed lazily,
|
|
49
|
+
* memoized — a representation that is never requested as gzip never pays
|
|
50
|
+
* for it). */
|
|
51
|
+
interface EncodedRepresentation {
|
|
52
|
+
readonly etag: string;
|
|
53
|
+
readonly compressible: boolean;
|
|
54
|
+
body(coding: ContentCoding): Buffer;
|
|
55
|
+
}
|
|
56
|
+
declare function createEncodedRepresentation(identity: Buffer, opts: {
|
|
57
|
+
compressible: boolean;
|
|
58
|
+
etag?: string;
|
|
59
|
+
}): EncodedRepresentation;
|
|
60
|
+
/** Small LRU of representations. `stamp` is whatever identifies the source
|
|
61
|
+
* version (e.g. `${mtimeMs}:${size}`); a stamp mismatch rebuilds. Bounded
|
|
62
|
+
* because some keys fold in request-derived input (the injected base URL). */
|
|
63
|
+
interface RepresentationCache {
|
|
64
|
+
get(key: string, stamp: string, build: () => Promise<EncodedRepresentation> | EncodedRepresentation): Promise<EncodedRepresentation>;
|
|
65
|
+
readonly size: number;
|
|
66
|
+
}
|
|
67
|
+
declare function createRepresentationCache(maxEntries?: number): RepresentationCache;
|
|
68
|
+
/** Write `rep` to `res` with `headers` (content-type, cache-control, frame
|
|
69
|
+
* headers — whatever the route decided), adding `etag`, `vary:
|
|
70
|
+
* accept-encoding`, `content-encoding` and `content-length`. A matching
|
|
71
|
+
* `if-none-match` answers 304 with the same headers and no body, so a
|
|
72
|
+
* revalidation refreshes the stored headers exactly as a 200 would. */
|
|
73
|
+
declare function sendRepresentation(req: IncomingMessage, res: ServerResponse, rep: EncodedRepresentation, headers: Record<string, string>): void;
|
|
74
|
+
|
|
75
|
+
export { APP_UI_MIME_BY_EXT, type ContentCoding, type EncodedRepresentation, IMMUTABLE_CACHE_CONTROL, type RepresentationCache, appUiContentType, createEncodedRepresentation, createRepresentationCache, ifNoneMatchHits, isCompressibleContentType, isValidAppUiAssetName, negotiateContentEncoding, sendRepresentation, strongEtag };
|
|
@@ -0,0 +1,144 @@
|
|
|
1
|
+
import { createHash } from 'crypto';
|
|
2
|
+
import { brotliCompressSync, constants, gzipSync } from 'zlib';
|
|
3
|
+
|
|
4
|
+
/**
|
|
5
|
+
* @agentproto/runtime v0.1.0-alpha
|
|
6
|
+
* Long-running gateway: MCP server + HTTP transport + HEARTBEAT autonomy + conversation persistence over a workspace dir.
|
|
7
|
+
*/
|
|
8
|
+
|
|
9
|
+
function negotiateContentEncoding(header) {
|
|
10
|
+
const raw = Array.isArray(header) ? header.join(",") : header;
|
|
11
|
+
if (!raw) return "identity";
|
|
12
|
+
const q = /* @__PURE__ */ new Map();
|
|
13
|
+
for (const part of raw.split(",")) {
|
|
14
|
+
const [name, ...params] = part.trim().toLowerCase().split(";");
|
|
15
|
+
if (!name) continue;
|
|
16
|
+
let weight = 1;
|
|
17
|
+
for (const p of params) {
|
|
18
|
+
const m = p.trim().match(/^q=([0-9.]+)$/);
|
|
19
|
+
if (m) weight = Number(m[1]);
|
|
20
|
+
}
|
|
21
|
+
q.set(name === "x-gzip" ? "gzip" : name, Number.isFinite(weight) ? weight : 0);
|
|
22
|
+
}
|
|
23
|
+
const acceptable = (coding) => {
|
|
24
|
+
const v = q.get(coding) ?? q.get("*");
|
|
25
|
+
return v !== void 0 && v > 0;
|
|
26
|
+
};
|
|
27
|
+
if (acceptable("br")) return "br";
|
|
28
|
+
if (acceptable("gzip")) return "gzip";
|
|
29
|
+
return "identity";
|
|
30
|
+
}
|
|
31
|
+
function strongEtag(body, variant) {
|
|
32
|
+
const digest = createHash("sha256").update(body).digest("base64url");
|
|
33
|
+
return variant ? `"${digest}-${variant}"` : `"${digest}"`;
|
|
34
|
+
}
|
|
35
|
+
function ifNoneMatchHits(header, etag) {
|
|
36
|
+
const raw = Array.isArray(header) ? header.join(",") : header;
|
|
37
|
+
if (!raw) return false;
|
|
38
|
+
const bare = etag.replace(/^W\//, "");
|
|
39
|
+
for (const part of raw.split(",")) {
|
|
40
|
+
const tag = part.trim();
|
|
41
|
+
if (tag === "*") return true;
|
|
42
|
+
if (tag.replace(/^W\//, "") === bare) return true;
|
|
43
|
+
}
|
|
44
|
+
return false;
|
|
45
|
+
}
|
|
46
|
+
var APP_UI_MIME_BY_EXT = {
|
|
47
|
+
".html": "text/html; charset=utf-8",
|
|
48
|
+
".htm": "text/html; charset=utf-8",
|
|
49
|
+
".js": "text/javascript; charset=utf-8",
|
|
50
|
+
".mjs": "text/javascript; charset=utf-8",
|
|
51
|
+
".css": "text/css; charset=utf-8",
|
|
52
|
+
".json": "application/json; charset=utf-8",
|
|
53
|
+
".webmanifest": "application/manifest+json; charset=utf-8",
|
|
54
|
+
".map": "application/json; charset=utf-8",
|
|
55
|
+
".svg": "image/svg+xml",
|
|
56
|
+
".png": "image/png",
|
|
57
|
+
".jpg": "image/jpeg",
|
|
58
|
+
".jpeg": "image/jpeg",
|
|
59
|
+
".gif": "image/gif",
|
|
60
|
+
".webp": "image/webp",
|
|
61
|
+
".ico": "image/x-icon",
|
|
62
|
+
".woff": "font/woff",
|
|
63
|
+
".woff2": "font/woff2",
|
|
64
|
+
".ttf": "font/ttf",
|
|
65
|
+
".txt": "text/plain; charset=utf-8",
|
|
66
|
+
".wasm": "application/wasm"
|
|
67
|
+
};
|
|
68
|
+
function appUiContentType(ext) {
|
|
69
|
+
const key = (ext.startsWith(".") ? ext : `.${ext}`).toLowerCase();
|
|
70
|
+
return APP_UI_MIME_BY_EXT[key] ?? "application/octet-stream";
|
|
71
|
+
}
|
|
72
|
+
function isCompressibleContentType(contentType) {
|
|
73
|
+
const base = contentType.split(";")[0].trim().toLowerCase();
|
|
74
|
+
return base.startsWith("text/") || base === "application/json" || base === "application/javascript" || base === "image/svg+xml" || base === "application/wasm";
|
|
75
|
+
}
|
|
76
|
+
function isValidAppUiAssetName(file) {
|
|
77
|
+
return /^[A-Za-z0-9_-][A-Za-z0-9._-]*$/.test(file);
|
|
78
|
+
}
|
|
79
|
+
var IMMUTABLE_CACHE_CONTROL = "public, max-age=31536000, immutable";
|
|
80
|
+
function createEncodedRepresentation(identity, opts) {
|
|
81
|
+
const encoded = /* @__PURE__ */ new Map([["identity", identity]]);
|
|
82
|
+
return {
|
|
83
|
+
etag: opts.etag ?? strongEtag(identity),
|
|
84
|
+
compressible: opts.compressible,
|
|
85
|
+
body(coding) {
|
|
86
|
+
const hit = encoded.get(coding);
|
|
87
|
+
if (hit) return hit;
|
|
88
|
+
const out = coding === "br" ? brotliCompressSync(identity, {
|
|
89
|
+
params: {
|
|
90
|
+
[constants.BROTLI_PARAM_QUALITY]: 5,
|
|
91
|
+
[constants.BROTLI_PARAM_SIZE_HINT]: identity.length
|
|
92
|
+
}
|
|
93
|
+
}) : gzipSync(identity, { level: 6 });
|
|
94
|
+
encoded.set(coding, out);
|
|
95
|
+
return out;
|
|
96
|
+
}
|
|
97
|
+
};
|
|
98
|
+
}
|
|
99
|
+
function createRepresentationCache(maxEntries = 64) {
|
|
100
|
+
const entries = /* @__PURE__ */ new Map();
|
|
101
|
+
return {
|
|
102
|
+
async get(key, stamp, build) {
|
|
103
|
+
const hit = entries.get(key);
|
|
104
|
+
if (hit && hit.stamp === stamp) {
|
|
105
|
+
entries.delete(key);
|
|
106
|
+
entries.set(key, hit);
|
|
107
|
+
return hit.rep;
|
|
108
|
+
}
|
|
109
|
+
const rep = await build();
|
|
110
|
+
entries.delete(key);
|
|
111
|
+
entries.set(key, { stamp, rep });
|
|
112
|
+
while (entries.size > maxEntries) {
|
|
113
|
+
const oldest = entries.keys().next().value;
|
|
114
|
+
if (oldest === void 0) break;
|
|
115
|
+
entries.delete(oldest);
|
|
116
|
+
}
|
|
117
|
+
return rep;
|
|
118
|
+
},
|
|
119
|
+
get size() {
|
|
120
|
+
return entries.size;
|
|
121
|
+
}
|
|
122
|
+
};
|
|
123
|
+
}
|
|
124
|
+
function sendRepresentation(req, res, rep, headers) {
|
|
125
|
+
const prior = res.getHeader("vary");
|
|
126
|
+
const priorVary = Array.isArray(prior) ? prior.join(", ") : prior === void 0 ? "" : String(prior);
|
|
127
|
+
const vary = /(^|,)\s*accept-encoding\s*(,|$)/i.test(priorVary) ? priorVary : priorVary ? `${priorVary}, accept-encoding` : "accept-encoding";
|
|
128
|
+
const out = { ...headers, etag: rep.etag, vary };
|
|
129
|
+
if (ifNoneMatchHits(req.headers["if-none-match"], rep.etag)) {
|
|
130
|
+
res.writeHead(304, out);
|
|
131
|
+
res.end();
|
|
132
|
+
return;
|
|
133
|
+
}
|
|
134
|
+
const coding = rep.compressible ? negotiateContentEncoding(req.headers["accept-encoding"]) : "identity";
|
|
135
|
+
const body = rep.body(coding);
|
|
136
|
+
if (coding !== "identity") out["content-encoding"] = coding;
|
|
137
|
+
out["content-length"] = String(body.length);
|
|
138
|
+
res.writeHead(200, out);
|
|
139
|
+
res.end(req.method === "HEAD" ? void 0 : body);
|
|
140
|
+
}
|
|
141
|
+
|
|
142
|
+
export { APP_UI_MIME_BY_EXT, IMMUTABLE_CACHE_CONTROL, appUiContentType, createEncodedRepresentation, createRepresentationCache, ifNoneMatchHits, isCompressibleContentType, isValidAppUiAssetName, negotiateContentEncoding, sendRepresentation, strongEtag };
|
|
143
|
+
//# sourceMappingURL=app-ui-delivery.mjs.map
|
|
144
|
+
//# sourceMappingURL=app-ui-delivery.mjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/app-ui-delivery.ts"],"names":["zlibConstants"],"mappings":"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","file":"app-ui-delivery.mjs","sourcesContent":["/**\n * HTTP delivery primitives for the app-UI shell — `GET /apps/:appId/ui` and\n * `GET /apps/:appId/ui/assets/:file` on the daemon (http-server.ts), and the\n * same shapes under `agentproto app serve` (cli/src/app-serve.ts). One\n * module so both hosts negotiate, validate and cache identically:\n *\n * - `accept-encoding` negotiation (`br` preferred, then `gzip`, else\n * identity) with `vary: accept-encoding` on every response.\n * - A strong `etag` (sha256 of the exact bytes served) answered with 304\n * on a matching `if-none-match`.\n * - An LRU of encoded representations keyed by a caller-chosen key and\n * invalidated by a caller-chosen stamp (path + mtime + size for files),\n * so neither the digest nor the compression reruns until the file\n * changes.\n *\n * Deliberately scoped to the shell: SSE, MCP and every API route keep their\n * own framing and never go through here.\n */\n\nimport { createHash } from \"node:crypto\"\nimport type { IncomingMessage, ServerResponse } from \"node:http\"\nimport { brotliCompressSync, constants as zlibConstants, gzipSync } from \"node:zlib\"\n\nexport type ContentCoding = \"br\" | \"gzip\" | \"identity\"\n\n/** Pick the response coding from an `accept-encoding` header: `br` when\n * acceptable, then `gzip`, else identity. q-values are honoured only as\n * acceptable (`q>0`) vs refused (`q=0`) — the preference order is ours, not\n * the client's. A `*` entry covers codings the header doesn't name. */\nexport function negotiateContentEncoding(header: string | string[] | undefined): ContentCoding {\n const raw = Array.isArray(header) ? header.join(\",\") : header\n if (!raw) return \"identity\"\n const q = new Map<string, number>()\n for (const part of raw.split(\",\")) {\n const [name, ...params] = part.trim().toLowerCase().split(\";\")\n if (!name) continue\n let weight = 1\n for (const p of params) {\n const m = p.trim().match(/^q=([0-9.]+)$/)\n if (m) weight = Number(m[1])\n }\n q.set(name === \"x-gzip\" ? \"gzip\" : name, Number.isFinite(weight) ? weight : 0)\n }\n const acceptable = (coding: string): boolean => {\n const v = q.get(coding) ?? q.get(\"*\")\n return v !== undefined && v > 0\n }\n if (acceptable(\"br\")) return \"br\"\n if (acceptable(\"gzip\")) return \"gzip\"\n return \"identity\"\n}\n\n/** Strong entity tag over `body` (sha256, base64url). `variant`, when set,\n * is appended so two representations of the same bytes that carry\n * different response headers (e.g. with/without frame headers) never\n * validate each other's cache entry. */\nexport function strongEtag(body: Buffer | string, variant?: string): string {\n const digest = createHash(\"sha256\").update(body).digest(\"base64url\")\n return variant ? `\"${digest}-${variant}\"` : `\"${digest}\"`\n}\n\n/** `if-none-match` evaluation (RFC 9110 §13.1.2): `*` or any listed tag\n * equal to `etag` under weak comparison. */\nexport function ifNoneMatchHits(header: string | string[] | undefined, etag: string): boolean {\n const raw = Array.isArray(header) ? header.join(\",\") : header\n if (!raw) return false\n const bare = etag.replace(/^W\\//, \"\")\n for (const part of raw.split(\",\")) {\n const tag = part.trim()\n if (tag === \"*\") return true\n if (tag.replace(/^W\\//, \"\") === bare) return true\n }\n return false\n}\n\n/** Content types the app-UI routes serve, by lowercase extension. */\nexport const APP_UI_MIME_BY_EXT: Readonly<Record<string, string>> = {\n \".html\": \"text/html; charset=utf-8\",\n \".htm\": \"text/html; charset=utf-8\",\n \".js\": \"text/javascript; charset=utf-8\",\n \".mjs\": \"text/javascript; charset=utf-8\",\n \".css\": \"text/css; charset=utf-8\",\n \".json\": \"application/json; charset=utf-8\",\n \".webmanifest\": \"application/manifest+json; charset=utf-8\",\n \".map\": \"application/json; charset=utf-8\",\n \".svg\": \"image/svg+xml\",\n \".png\": \"image/png\",\n \".jpg\": \"image/jpeg\",\n \".jpeg\": \"image/jpeg\",\n \".gif\": \"image/gif\",\n \".webp\": \"image/webp\",\n \".ico\": \"image/x-icon\",\n \".woff\": \"font/woff\",\n \".woff2\": \"font/woff2\",\n \".ttf\": \"font/ttf\",\n \".txt\": \"text/plain; charset=utf-8\",\n \".wasm\": \"application/wasm\",\n}\n\n/** Content type for an extension (with or without the leading dot). */\nexport function appUiContentType(ext: string): string {\n const key = (ext.startsWith(\".\") ? ext : `.${ext}`).toLowerCase()\n return APP_UI_MIME_BY_EXT[key] ?? \"application/octet-stream\"\n}\n\n/** Whether a content type is worth compressing — text-ish only; woff2/png\n * and friends are already compressed. */\nexport function isCompressibleContentType(contentType: string): boolean {\n const base = contentType.split(\";\")[0]!.trim().toLowerCase()\n return (\n base.startsWith(\"text/\") ||\n base === \"application/json\" ||\n base === \"application/javascript\" ||\n base === \"image/svg+xml\" ||\n base === \"application/wasm\"\n )\n}\n\n/** `:file` segment of the assets route: a flat name from `[A-Za-z0-9._-]`,\n * not starting with `.` (so no `.`/`..`, no dotfiles), no separators. */\nexport function isValidAppUiAssetName(file: string): boolean {\n return /^[A-Za-z0-9_-][A-Za-z0-9._-]*$/.test(file)\n}\n\n/** Assets route cache policy — Vite emits content-hashed file names. */\nexport const IMMUTABLE_CACHE_CONTROL = \"public, max-age=31536000, immutable\"\n\n/** One servable body, its strong etag, and its encodings (computed lazily,\n * memoized — a representation that is never requested as gzip never pays\n * for it). */\nexport interface EncodedRepresentation {\n readonly etag: string\n readonly compressible: boolean\n body(coding: ContentCoding): Buffer\n}\n\nexport function createEncodedRepresentation(\n identity: Buffer,\n opts: { compressible: boolean; etag?: string },\n): EncodedRepresentation {\n const encoded = new Map<ContentCoding, Buffer>([[\"identity\", identity]])\n return {\n etag: opts.etag ?? strongEtag(identity),\n compressible: opts.compressible,\n body(coding) {\n const hit = encoded.get(coding)\n if (hit) return hit\n const out =\n coding === \"br\"\n ? brotliCompressSync(identity, {\n params: {\n [zlibConstants.BROTLI_PARAM_QUALITY]: 5,\n [zlibConstants.BROTLI_PARAM_SIZE_HINT]: identity.length,\n },\n })\n : gzipSync(identity, { level: 6 })\n encoded.set(coding, out)\n return out\n },\n }\n}\n\n/** Small LRU of representations. `stamp` is whatever identifies the source\n * version (e.g. `${mtimeMs}:${size}`); a stamp mismatch rebuilds. Bounded\n * because some keys fold in request-derived input (the injected base URL). */\nexport interface RepresentationCache {\n get(\n key: string,\n stamp: string,\n build: () => Promise<EncodedRepresentation> | EncodedRepresentation,\n ): Promise<EncodedRepresentation>\n readonly size: number\n}\n\nexport function createRepresentationCache(maxEntries = 64): RepresentationCache {\n const entries = new Map<string, { stamp: string; rep: EncodedRepresentation }>()\n return {\n async get(key, stamp, build) {\n const hit = entries.get(key)\n if (hit && hit.stamp === stamp) {\n entries.delete(key)\n entries.set(key, hit)\n return hit.rep\n }\n const rep = await build()\n entries.delete(key)\n entries.set(key, { stamp, rep })\n while (entries.size > maxEntries) {\n const oldest = entries.keys().next().value\n if (oldest === undefined) break\n entries.delete(oldest)\n }\n return rep\n },\n get size() {\n return entries.size\n },\n }\n}\n\n/** Write `rep` to `res` with `headers` (content-type, cache-control, frame\n * headers — whatever the route decided), adding `etag`, `vary:\n * accept-encoding`, `content-encoding` and `content-length`. A matching\n * `if-none-match` answers 304 with the same headers and no body, so a\n * revalidation refreshes the stored headers exactly as a 200 would. */\nexport function sendRepresentation(\n req: IncomingMessage,\n res: ServerResponse,\n rep: EncodedRepresentation,\n headers: Record<string, string>,\n): void {\n // Merge, don't clobber: the daemon's CORS layer may already have set\n // `Vary: Origin` via setHeader, which a writeHead `vary` would replace.\n const prior = res.getHeader(\"vary\")\n const priorVary = Array.isArray(prior) ? prior.join(\", \") : prior === undefined ? \"\" : String(prior)\n const vary = /(^|,)\\s*accept-encoding\\s*(,|$)/i.test(priorVary)\n ? priorVary\n : priorVary\n ? `${priorVary}, accept-encoding`\n : \"accept-encoding\"\n const out: Record<string, string> = { ...headers, etag: rep.etag, vary }\n if (ifNoneMatchHits(req.headers[\"if-none-match\"], rep.etag)) {\n res.writeHead(304, out)\n res.end()\n return\n }\n const coding = rep.compressible ? negotiateContentEncoding(req.headers[\"accept-encoding\"]) : \"identity\"\n const body = rep.body(coding)\n if (coding !== \"identity\") out[\"content-encoding\"] = coding\n out[\"content-length\"] = String(body.length)\n res.writeHead(200, out)\n res.end(req.method === \"HEAD\" ? undefined : body)\n}\n"]}
|
package/dist/catalog-models.d.ts
CHANGED
|
@@ -1,8 +1,10 @@
|
|
|
1
1
|
import { AuthProfile } from '@agentproto/auth';
|
|
2
|
-
import { A as AdapterAuthDescriptor } from './spawn-defaults-
|
|
3
|
-
import { R as RouteSpec } from './session-config-
|
|
2
|
+
import { A as AdapterAuthDescriptor } from './spawn-defaults-CZj39Znq.js';
|
|
3
|
+
import { R as RouteSpec } from './session-config-ByfVeEQJ.js';
|
|
4
|
+
import './context-continuity-Bn99UtVC.js';
|
|
5
|
+
import '@agentproto/acp';
|
|
6
|
+
import '@agentproto/command-sandbox';
|
|
4
7
|
import '@agentproto/model-catalog';
|
|
5
|
-
import './context-continuity-ib9_bVYM.js';
|
|
6
8
|
|
|
7
9
|
/**
|
|
8
10
|
* Read-only catalog/vendor endpoint (`agentproto-session-config-axes`
|