dsh-claude-style 0.16.0-dev.27 → 0.16.1-dev.31

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (41) hide show
  1. package/CHANGELOG.md +62 -0
  2. package/LICENSE +3 -2
  3. package/README.en.md +1 -0
  4. package/README.md +6 -0
  5. package/THIRD_PARTY_NOTICES.md +2 -0
  6. package/docs/FEATURES.en.md +4 -3
  7. package/docs/FEATURES.md +4 -3
  8. package/docs/SETTINGS.en.md +12 -6
  9. package/docs/SETTINGS.md +12 -6
  10. package/docs/STYLE.md +40 -1
  11. package/lib/assets/0443f196403b.js.br +0 -0
  12. package/lib/assets/39f1a2e69bb7.js.br +0 -0
  13. package/lib/assets/4d55814bc60a.js.br +0 -0
  14. package/lib/assets/6c257991027d.js.br +0 -0
  15. package/lib/assets/9abad5da303e.js.br +0 -0
  16. package/lib/assets/b55a1acf34e0.js.br +0 -0
  17. package/lib/assets/d2064c247435.js.br +0 -0
  18. package/lib/assets/manifest.json +28 -28
  19. package/lib/client.js +37 -11
  20. package/lib/host/brand.js +70 -1
  21. package/lib/host/cache-file.js +63 -25
  22. package/lib/host/harness-home.js +7 -3
  23. package/lib/host/index.js +4 -1
  24. package/lib/host/package-root.js +15 -13
  25. package/lib/host/peakrate.js +7 -4
  26. package/lib/host/routes.js +164 -72
  27. package/lib/host/search.js +44 -2
  28. package/lib/host/settings.js +137 -43
  29. package/lib/host/usage-record.js +5 -2
  30. package/lib/host/usage.js +57 -5
  31. package/lib/model-descriptions.json +0 -1322
  32. package/package.json +1 -1
  33. package/lib/assets/1cefeb3d67c7.js.br +0 -0
  34. package/lib/assets/1da1959a3cb1.js.br +0 -0
  35. package/lib/assets/2c3bd0b6c22c.js.br +0 -0
  36. package/lib/assets/34d559377558.js.br +0 -0
  37. package/lib/assets/acf9cf79c43e.js.br +0 -0
  38. package/lib/assets/b7ec75cf39a7.js.br +0 -0
  39. package/lib/assets/dab5fb383802.js.br +0 -0
  40. package/lib/host/http.js +0 -74
  41. package/lib/host/session-events.js +0 -40
package/lib/host/brand.js CHANGED
@@ -24,7 +24,76 @@ var PEAKRATE_PATH = `${ROUTE_PREFIX}/peakrate`;
24
24
  import { mkdirSync, readFileSync, renameSync, rmSync, statSync, writeFileSync } from "node:fs";
25
25
  import { join } from "node:path";
26
26
  import { pluginPath } from "./harness-home.js";
27
- import { fenceRefused, methodRefused, readRequestBody, sendJson } from "./http.js";
27
+
28
+ // packages/engine/node/http.ts
29
+ function refusalOf(ctx, req) {
30
+ const connection = ctx.get("connection");
31
+ if (typeof connection?.requestRejection === "function") return connection.requestRejection(req);
32
+ if (!isLoopbackPeer(req.socket.remoteAddress)) return 403;
33
+ const host = req.headers.host;
34
+ if (host !== void 0) {
35
+ if (!URL.canParse(`http://${host}`)) return 403;
36
+ const name = new URL(`http://${host}`).hostname;
37
+ if (name !== "localhost" && name !== "[::1]" && !/^127\.\d+\.\d+\.\d+$/.test(name)) return 403;
38
+ }
39
+ const site = req.headers["sec-fetch-site"];
40
+ if (site !== void 0 && site !== "same-origin" && site !== "none") return 403;
41
+ const origin = req.headers.origin;
42
+ if (origin === void 0) return void 0;
43
+ if (!URL.canParse(origin)) return 403;
44
+ return new URL(origin).host === host ? void 0 : 403;
45
+ }
46
+ function isLoopbackPeer(address) {
47
+ if (address === void 0) return false;
48
+ const plain = address.startsWith("::ffff:") ? address.slice("::ffff:".length) : address;
49
+ return plain === "::1" || /^127\.\d{1,3}\.\d{1,3}\.\d{1,3}$/.test(plain);
50
+ }
51
+ function sendJson(res, status, payload) {
52
+ const body = Buffer.from(JSON.stringify(payload));
53
+ res.writeHead(status, {
54
+ "content-type": "application/json; charset=utf-8",
55
+ "content-length": String(body.byteLength),
56
+ "cache-control": "no-store"
57
+ });
58
+ res.end(body);
59
+ }
60
+ function methodRefused(req, res, methods) {
61
+ if (req.method !== void 0 && methods.includes(req.method)) return false;
62
+ res.writeHead(405, { allow: methods.join(", ") });
63
+ res.end();
64
+ return true;
65
+ }
66
+ function fenceRefused(ctx, req, res) {
67
+ const refused = refusalOf(ctx, req);
68
+ if (refused === void 0) return false;
69
+ sendJson(res, refused, { ok: false, error: refused === 401 ? "unauthorized" : "forbidden" });
70
+ return true;
71
+ }
72
+ function readRequestBody(req, limit) {
73
+ return new Promise((settle) => {
74
+ const chunks = [];
75
+ let size = 0;
76
+ let over = false;
77
+ req.on("data", (chunk) => {
78
+ if (over) return;
79
+ size += chunk.length;
80
+ if (size > limit) {
81
+ over = true;
82
+ settle(null);
83
+ return;
84
+ }
85
+ chunks.push(Buffer.from(chunk));
86
+ });
87
+ req.on("end", () => {
88
+ if (!over) settle(Buffer.concat(chunks));
89
+ });
90
+ req.on("error", () => {
91
+ if (!over) settle(null);
92
+ });
93
+ });
94
+ }
95
+
96
+ // packages/host/src/brand.ts
28
97
  var IMAGE_PATHS = { mark: BRAND_MARK_PATH, wordmark: BRAND_WORDMARK_PATH };
29
98
  var IMAGE_HEADERS = {
30
99
  "cache-control": "no-cache",
@@ -1,31 +1,69 @@
1
- // packages/host/src/cache-file.ts
1
+ // packages/contracts/src/package.ts
2
+ var PACKAGE_NAME = "dsh-claude-style";
3
+
4
+ // packages/engine/node/cache-file.ts
2
5
  import { existsSync, mkdirSync, readFileSync, renameSync, writeFileSync } from "node:fs";
3
- import { dirname, join } from "node:path";
4
- import { harnessPath } from "./harness-home.js";
5
- function cachePath(ctx, ...segments) {
6
- return join(harnessPath(ctx, "cache", "dsh-claude-style"), ...segments);
7
- }
8
- function readJsonDocument(ctx, path, label) {
9
- if (!existsSync(path)) return void 0;
10
- try {
11
- return JSON.parse(readFileSync(path, "utf8"));
12
- } catch (error) {
13
- ctx.logger?.warn?.(`dsh-claude-style: ${label} unreadable (${error.message})`);
14
- return void 0;
15
- }
6
+ import { dirname, join as join2 } from "node:path";
7
+
8
+ // packages/engine/node/harness-home.ts
9
+ import { homedir } from "node:os";
10
+ import { join } from "node:path";
11
+ function harnessPath(ctx, ...segments) {
12
+ const resolvePath = ctx.get("dshHomePath");
13
+ if (typeof resolvePath === "function") return resolvePath(...segments);
14
+ return join(process.env.DSH_HOME ?? join(homedir(), ".dsh"), ...segments);
16
15
  }
17
- function writeJsonDocument(ctx, path, label, document) {
18
- const temporary = `${path}.${process.pid}.tmp`;
19
- try {
20
- mkdirSync(dirname(path), { recursive: true });
21
- writeFileSync(temporary, JSON.stringify(document), "utf8");
22
- renameSync(temporary, path);
23
- return true;
24
- } catch (error) {
25
- ctx.logger?.warn?.(`dsh-claude-style: ${label} not written: ${error.message}`);
26
- return false;
27
- }
16
+
17
+ // packages/engine/node/cache-file.ts
18
+ function createCacheFiles(packageName) {
19
+ return {
20
+ /** One path inside this plugin's cache directory in the harness home. */
21
+ cachePath(ctx, ...segments) {
22
+ return join2(harnessPath(ctx, "cache", packageName), ...segments);
23
+ },
24
+ /**
25
+ * One JSON document from disk.
26
+ *
27
+ * @param ctx - host plugin context, for the warning a failure leaves.
28
+ * @param path - the file to read.
29
+ * @param label - what the file is, for the warning.
30
+ * @returns the parsed document, or undefined when it is absent or unreadable.
31
+ */
32
+ readJsonDocument(ctx, path, label) {
33
+ if (!existsSync(path)) return void 0;
34
+ try {
35
+ return JSON.parse(readFileSync(path, "utf8"));
36
+ } catch (error) {
37
+ ctx.logger?.warn?.(`${packageName}: ${label} unreadable (${error.message})`);
38
+ return void 0;
39
+ }
40
+ },
41
+ /**
42
+ * Replace one cache file through a temporary file.
43
+ *
44
+ * @param ctx - host plugin context, for the warning a failure leaves.
45
+ * @param path - the file to write.
46
+ * @param label - what the file is, for the warning.
47
+ * @param document - the value to store.
48
+ * @returns whether the file now holds the document.
49
+ */
50
+ writeJsonDocument(ctx, path, label, document) {
51
+ const temporary = `${path}.${process.pid}.tmp`;
52
+ try {
53
+ mkdirSync(dirname(path), { recursive: true });
54
+ writeFileSync(temporary, JSON.stringify(document), "utf8");
55
+ renameSync(temporary, path);
56
+ return true;
57
+ } catch (error) {
58
+ ctx.logger?.warn?.(`${packageName}: ${label} not written: ${error.message}`);
59
+ return false;
60
+ }
61
+ }
62
+ };
28
63
  }
64
+
65
+ // packages/host/src/cache-file.ts
66
+ var { cachePath, readJsonDocument, writeJsonDocument } = createCacheFiles(PACKAGE_NAME);
29
67
  export {
30
68
  cachePath,
31
69
  readJsonDocument,
@@ -1,4 +1,7 @@
1
- // packages/host/src/harness-home.ts
1
+ // packages/contracts/src/package.ts
2
+ var PACKAGE_NAME = "dsh-claude-style";
3
+
4
+ // packages/engine/node/harness-home.ts
2
5
  import { homedir } from "node:os";
3
6
  import { join } from "node:path";
4
7
  function harnessPath(ctx, ...segments) {
@@ -6,10 +9,11 @@ function harnessPath(ctx, ...segments) {
6
9
  if (typeof resolvePath === "function") return resolvePath(...segments);
7
10
  return join(process.env.DSH_HOME ?? join(homedir(), ".dsh"), ...segments);
8
11
  }
12
+
13
+ // packages/host/src/harness-home.ts
9
14
  function pluginPath(ctx, ...segments) {
10
- return harnessPath(ctx, "dsh-claude-style", ...segments);
15
+ return harnessPath(ctx, PACKAGE_NAME, ...segments);
11
16
  }
12
17
  export {
13
- harnessPath,
14
18
  pluginPath
15
19
  };
package/lib/host/index.js CHANGED
@@ -1,8 +1,11 @@
1
+ // packages/contracts/src/package.ts
2
+ var PACKAGE_NAME = "dsh-claude-style";
3
+
1
4
  // packages/host/src/index.ts
2
5
  import { registerRoutes } from "./routes.js";
3
6
  import { registerSettings } from "./settings.js";
4
7
  import { Config } from "./settings.js";
5
- var name = "dsh-claude-style";
8
+ var name = PACKAGE_NAME;
6
9
  function apply(ctx) {
7
10
  if (typeof ctx.inject === "function") ctx.inject(["webServer"], (scope) => {
8
11
  registerRoutes(ctx, scope);
@@ -1,24 +1,26 @@
1
- // packages/host/src/package-root.ts
1
+ // packages/contracts/src/package.ts
2
+ var PACKAGE_NAME = "dsh-claude-style";
3
+
4
+ // packages/engine/node/package-root.ts
2
5
  import { existsSync, readFileSync } from "node:fs";
3
6
  import { dirname, join, parse } from "node:path";
4
7
  import { fileURLToPath } from "node:url";
5
- var cached = null;
6
- function packageRoot() {
7
- if (cached !== null) return cached;
8
- let at = dirname(fileURLToPath(import.meta.url));
8
+ function findPackageRoot(moduleUrl, packageName) {
9
+ let at = dirname(fileURLToPath(moduleUrl));
9
10
  const top = parse(at).root;
10
11
  while (at !== top) {
11
12
  const manifest = join(at, "package.json");
12
- if (existsSync(manifest)) {
13
- const parsed = JSON.parse(readFileSync(manifest, "utf8"));
14
- if (parsed.dsh !== void 0) {
15
- cached = at;
16
- return cached;
17
- }
18
- }
13
+ if (existsSync(manifest) && JSON.parse(readFileSync(manifest, "utf8")).dsh !== void 0) return at;
19
14
  at = dirname(at);
20
15
  }
21
- throw new Error("dsh-claude-style: no package.json with a dsh field above the host half");
16
+ throw new Error(`${packageName}: no package.json with a dsh field above the host half`);
17
+ }
18
+
19
+ // packages/host/src/package-root.ts
20
+ var cached = null;
21
+ function packageRoot() {
22
+ cached ??= findPackageRoot(import.meta.url, PACKAGE_NAME);
23
+ return cached;
22
24
  }
23
25
  export {
24
26
  packageRoot
@@ -1,3 +1,6 @@
1
+ // packages/contracts/src/package.ts
2
+ var PACKAGE_NAME = "dsh-claude-style";
3
+
1
4
  // packages/host/src/peakrate.ts
2
5
  import { statSync } from "node:fs";
3
6
  import { join } from "node:path";
@@ -23,7 +26,7 @@ function createPeakRate(ctx) {
23
26
  function shippedCatalog() {
24
27
  const parsed = parseCatalog(readJsonDocument(ctx, snapshotFile, `lib/${PEAKRATE_CATALOG_FILE}`));
25
28
  if (parsed === null) {
26
- warn(`dsh-claude-style: lib/${PEAKRATE_CATALOG_FILE} is not a catalog this build understands`);
29
+ warn(`${PACKAGE_NAME}: lib/${PEAKRATE_CATALOG_FILE} is not a catalog this build understands`);
27
30
  return void 0;
28
31
  }
29
32
  return parsed;
@@ -62,7 +65,7 @@ function createPeakRate(ctx) {
62
65
  try {
63
66
  const response = await fetch(PEAKRATE_CATALOG_URL, { signal: controller.signal });
64
67
  if (!response.ok) {
65
- warn(`dsh-claude-style: peak rate source answered ${response.status}; keeping the current catalog`);
68
+ warn(`${PACKAGE_NAME}: peak rate source answered ${response.status}; keeping the current catalog`);
66
69
  return false;
67
70
  }
68
71
  raw = await response.json();
@@ -71,12 +74,12 @@ function createPeakRate(ctx) {
71
74
  if (inFlight === controller) inFlight = null;
72
75
  }
73
76
  } catch (error) {
74
- warn(`dsh-claude-style: peak rate source unreachable, keeping the current catalog: ${error.message}`);
77
+ warn(`${PACKAGE_NAME}: peak rate source unreachable, keeping the current catalog: ${error.message}`);
75
78
  return false;
76
79
  }
77
80
  const parsed = parseCatalog(raw);
78
81
  if (parsed === null) {
79
- warn("dsh-claude-style: peak rate source answered a document this build does not understand; keeping the current catalog");
82
+ warn(`${PACKAGE_NAME}: peak rate source answered a document this build does not understand; keeping the current catalog`);
80
83
  return false;
81
84
  }
82
85
  catalog = parsed;
@@ -1,3 +1,6 @@
1
+ // packages/contracts/src/package.ts
2
+ var PACKAGE_NAME = "dsh-claude-style";
3
+
1
4
  // packages/contracts/src/routes.ts
2
5
  var ROUTE_PREFIX = "/dsh-claude-style";
3
6
  var USERNAME_PATH = `${ROUTE_PREFIX}/username`;
@@ -12,13 +15,157 @@ var BRAND_WORDMARK_PATH = `${ROUTE_PREFIX}/brand/wordmark`;
12
15
  var PEAKRATE_PATH = `${ROUTE_PREFIX}/peakrate`;
13
16
 
14
17
  // packages/host/src/routes.ts
15
- import { existsSync, readFileSync, readdirSync, realpathSync, rmSync, statSync } from "node:fs";
18
+ import { existsSync as existsSync2, readFileSync as readFileSync2, readdirSync, realpathSync, rmSync, statSync } from "node:fs";
16
19
  import { userInfo } from "node:os";
17
- import { join, resolve, sep } from "node:path";
18
- import { brotliDecompressSync } from "node:zlib";
20
+ import { join as join3, resolve, sep } from "node:path";
19
21
  import { brandRoutes } from "./brand.js";
20
- import { harnessPath, pluginPath } from "./harness-home.js";
21
- import { fenceRefused, methodRefused, readRequestBody, refusalOf, sendJson } from "./http.js";
22
+
23
+ // packages/engine/node/harness-home.ts
24
+ import { homedir } from "node:os";
25
+ import { join } from "node:path";
26
+ function harnessPath(ctx, ...segments) {
27
+ const resolvePath = ctx.get("dshHomePath");
28
+ if (typeof resolvePath === "function") return resolvePath(...segments);
29
+ return join(process.env.DSH_HOME ?? join(homedir(), ".dsh"), ...segments);
30
+ }
31
+
32
+ // packages/host/src/routes.ts
33
+ import { pluginPath } from "./harness-home.js";
34
+
35
+ // packages/engine/node/http.ts
36
+ function refusalOf(ctx, req) {
37
+ const connection = ctx.get("connection");
38
+ if (typeof connection?.requestRejection === "function") return connection.requestRejection(req);
39
+ if (!isLoopbackPeer(req.socket.remoteAddress)) return 403;
40
+ const host = req.headers.host;
41
+ if (host !== void 0) {
42
+ if (!URL.canParse(`http://${host}`)) return 403;
43
+ const name = new URL(`http://${host}`).hostname;
44
+ if (name !== "localhost" && name !== "[::1]" && !/^127\.\d+\.\d+\.\d+$/.test(name)) return 403;
45
+ }
46
+ const site = req.headers["sec-fetch-site"];
47
+ if (site !== void 0 && site !== "same-origin" && site !== "none") return 403;
48
+ const origin = req.headers.origin;
49
+ if (origin === void 0) return void 0;
50
+ if (!URL.canParse(origin)) return 403;
51
+ return new URL(origin).host === host ? void 0 : 403;
52
+ }
53
+ function isLoopbackPeer(address) {
54
+ if (address === void 0) return false;
55
+ const plain = address.startsWith("::ffff:") ? address.slice("::ffff:".length) : address;
56
+ return plain === "::1" || /^127\.\d{1,3}\.\d{1,3}\.\d{1,3}$/.test(plain);
57
+ }
58
+ function sendJson(res, status, payload) {
59
+ const body = Buffer.from(JSON.stringify(payload));
60
+ res.writeHead(status, {
61
+ "content-type": "application/json; charset=utf-8",
62
+ "content-length": String(body.byteLength),
63
+ "cache-control": "no-store"
64
+ });
65
+ res.end(body);
66
+ }
67
+ function methodRefused(req, res, methods) {
68
+ if (req.method !== void 0 && methods.includes(req.method)) return false;
69
+ res.writeHead(405, { allow: methods.join(", ") });
70
+ res.end();
71
+ return true;
72
+ }
73
+ function fenceRefused(ctx, req, res) {
74
+ const refused = refusalOf(ctx, req);
75
+ if (refused === void 0) return false;
76
+ sendJson(res, refused, { ok: false, error: refused === 401 ? "unauthorized" : "forbidden" });
77
+ return true;
78
+ }
79
+ function readRequestBody(req, limit) {
80
+ return new Promise((settle) => {
81
+ const chunks = [];
82
+ let size = 0;
83
+ let over = false;
84
+ req.on("data", (chunk) => {
85
+ if (over) return;
86
+ size += chunk.length;
87
+ if (size > limit) {
88
+ over = true;
89
+ settle(null);
90
+ return;
91
+ }
92
+ chunks.push(Buffer.from(chunk));
93
+ });
94
+ req.on("end", () => {
95
+ if (!over) settle(Buffer.concat(chunks));
96
+ });
97
+ req.on("error", () => {
98
+ if (!over) settle(null);
99
+ });
100
+ });
101
+ }
102
+
103
+ // packages/engine/node/static-files.ts
104
+ import { existsSync, readFileSync } from "node:fs";
105
+ import { join as join2 } from "node:path";
106
+ import { brotliDecompressSync } from "node:zlib";
107
+ var ASSETS_MANIFEST = "manifest.json";
108
+ function createStaticFiles(ctx, packageName, assetsDir) {
109
+ const unpressed = /* @__PURE__ */ new Map();
110
+ function sendFile(res, method, path, headers, body = null) {
111
+ if (body === null && !existsSync(path)) {
112
+ res.writeHead(404);
113
+ res.end();
114
+ return;
115
+ }
116
+ const payload = body ?? readFileSync(path);
117
+ res.writeHead(200, {
118
+ ...headers,
119
+ "content-length": String(payload.byteLength)
120
+ });
121
+ res.end(method === "HEAD" ? void 0 : payload);
122
+ }
123
+ function readManifest() {
124
+ const path = join2(assetsDir, ASSETS_MANIFEST);
125
+ if (!existsSync(path)) return void 0;
126
+ try {
127
+ return JSON.parse(readFileSync(path, "utf8")).assets;
128
+ } catch (error) {
129
+ ctx.logger?.warn?.(`${packageName}: lib/assets/${ASSETS_MANIFEST} is unreadable: ${error?.message ?? String(error)}`);
130
+ return void 0;
131
+ }
132
+ }
133
+ function sendAsset(req, res, name) {
134
+ const asset = readManifest()?.[name];
135
+ if (asset === void 0) return false;
136
+ const stored = join2(assetsDir, asset.encoding === "br" ? `${name}.br` : name);
137
+ const headers = {
138
+ "content-type": asset.type,
139
+ "cache-control": "public, max-age=31536000, immutable"
140
+ };
141
+ const method = req.method ?? "GET";
142
+ if (asset.encoding !== "br") {
143
+ sendFile(res, method, stored, headers);
144
+ return true;
145
+ }
146
+ if (/\bbr\b/.test(req.headers["accept-encoding"] ?? "")) {
147
+ sendFile(res, method, stored, { ...headers, "content-encoding": "br" });
148
+ return true;
149
+ }
150
+ const cached = unpressed.get(name);
151
+ if (cached !== void 0) {
152
+ sendFile(res, method, stored, headers, cached);
153
+ return true;
154
+ }
155
+ if (!existsSync(stored)) {
156
+ res.writeHead(404);
157
+ res.end();
158
+ return true;
159
+ }
160
+ const body = brotliDecompressSync(readFileSync(stored));
161
+ unpressed.set(name, body);
162
+ sendFile(res, method, stored, headers, body);
163
+ return true;
164
+ }
165
+ return { sendFile, sendAsset };
166
+ }
167
+
168
+ // packages/host/src/routes.ts
22
169
  import { createHdslAccount } from "./hdsl.js";
23
170
  import { packageRoot } from "./package-root.js";
24
171
  import { createPeakRate } from "./peakrate.js";
@@ -30,11 +177,11 @@ var FONT_FILES = {
30
177
  "JetBrainsMonoItalicVariable.ttf": "font/ttf",
31
178
  "AnthropicSansWebText.ttf": "font/ttf",
32
179
  "AnthropicSerifWebText.ttf": "font/ttf",
180
+ "AnthropicMonoWeb.ttf": "font/ttf",
33
181
  "InterVariable.woff2": "font/woff2",
34
182
  "NotoSerifVariable.woff2": "font/woff2"
35
183
  };
36
184
  var ASSETS_PATH = `${ROUTE_PREFIX}/assets/`;
37
- var ASSETS_MANIFEST = "manifest.json";
38
185
  var USAGE_TTL_MS = 5 * 60 * 1e3;
39
186
  var SESSION_ID_RE = /^[A-Za-z0-9][A-Za-z0-9._-]{0,199}$/;
40
187
  var DELETE_BODY_MAX = 4096;
@@ -86,7 +233,7 @@ async function deleteSession(ctx, req, res) {
86
233
  const root = resolve(harnessPath(ctx, "sessions"));
87
234
  let dir = null;
88
235
  for (const entry of readdirSync(root)) {
89
- const candidate = join(root, entry, sessionId);
236
+ const candidate = join3(root, entry, sessionId);
90
237
  if (statSync(candidate, { throwIfNoEntry: false })?.isDirectory() === true) {
91
238
  dir = candidate;
92
239
  break;
@@ -108,69 +255,14 @@ async function deleteSession(ctx, req, res) {
108
255
  }
109
256
  function registerRoutes(ctx, scope) {
110
257
  const root = packageRoot();
111
- const file = join(root, "lib", COPY_FILE);
112
- const fontsDir = join(root, "lib", "fonts");
258
+ const file = join3(root, "lib", COPY_FILE);
259
+ const fontsDir = join3(root, "lib", "fonts");
113
260
  const userFontsDir = () => pluginPath(ctx, "fonts");
114
- const assetsDir = join(root, "lib", "assets");
115
- const unpressed = /* @__PURE__ */ new Map();
116
- const sendFile = (res, method, path, headers, body = null) => {
117
- if (body === null && !existsSync(path)) {
118
- res.writeHead(404);
119
- res.end();
120
- return;
121
- }
122
- const payload = body ?? readFileSync(path);
123
- res.writeHead(200, {
124
- ...headers,
125
- "content-length": String(payload.byteLength)
126
- });
127
- res.end(method === "HEAD" ? void 0 : payload);
128
- };
129
- const sendAsset = (req, res, name) => {
130
- const manifest = readManifest();
131
- const asset = manifest?.[name];
132
- if (asset === void 0) return false;
133
- const stored = join(assetsDir, asset.encoding === "br" ? `${name}.br` : name);
134
- const headers = {
135
- "content-type": asset.type,
136
- "cache-control": "public, max-age=31536000, immutable"
137
- };
138
- if (asset.encoding === "br") {
139
- if (/\bbr\b/.test(req.headers["accept-encoding"] ?? "")) {
140
- sendFile(res, req.method ?? "GET", stored, { ...headers, "content-encoding": "br" });
141
- return true;
142
- }
143
- const cached = unpressed.get(name);
144
- if (cached !== void 0) {
145
- sendFile(res, req.method ?? "GET", stored, headers, cached);
146
- return true;
147
- }
148
- if (!existsSync(stored)) {
149
- res.writeHead(404);
150
- res.end();
151
- return true;
152
- }
153
- const body = brotliDecompressSync(readFileSync(stored));
154
- unpressed.set(name, body);
155
- sendFile(res, req.method ?? "GET", stored, headers, body);
156
- return true;
157
- }
158
- sendFile(res, req.method ?? "GET", stored, headers);
159
- return true;
160
- };
161
- const readManifest = () => {
162
- const path = join(assetsDir, ASSETS_MANIFEST);
163
- if (!existsSync(path)) return void 0;
164
- try {
165
- return JSON.parse(readFileSync(path, "utf8")).assets;
166
- } catch (error) {
167
- ctx.logger?.warn?.(`dsh-claude-style: lib/assets/${ASSETS_MANIFEST} is unreadable: ${error?.message ?? String(error)}`);
168
- return void 0;
169
- }
170
- };
261
+ const assetsDir = join3(root, "lib", "assets");
262
+ const { sendFile, sendAsset } = createStaticFiles(ctx, PACKAGE_NAME, assetsDir);
171
263
  scope.effect(() => {
172
264
  const disposers = [];
173
- const report = (message, error) => ctx.logger?.warn?.(`dsh-claude-style: ${message}: ${error?.message ?? String(error)}`);
265
+ const report = (message, error) => ctx.logger?.warn?.(`${PACKAGE_NAME}: ${message}: ${error?.message ?? String(error)}`);
174
266
  const server = scope.webServer;
175
267
  if (server === void 0 || server === null) {
176
268
  report("web server unavailable", new Error("the host carries no webServer service, so no route of this plugin is registered"));
@@ -211,8 +303,8 @@ function registerRoutes(ctx, scope) {
211
303
  const font = sub.startsWith("/fonts/") ? FONT_FILES[sub.slice("/fonts/".length)] : void 0;
212
304
  if (font !== void 0) {
213
305
  const name = sub.slice("/fonts/".length);
214
- const dropped = join(userFontsDir(), name);
215
- sendFile(res, req.method ?? "GET", existsSync(dropped) ? dropped : join(fontsDir, name), {
306
+ const dropped = join3(userFontsDir(), name);
307
+ sendFile(res, req.method ?? "GET", existsSync2(dropped) ? dropped : join3(fontsDir, name), {
216
308
  "content-type": font,
217
309
  "cache-control": "public, max-age=86400"
218
310
  });
@@ -265,12 +357,12 @@ function registerRoutes(ctx, scope) {
265
357
  if (methodRefused(req, res, ["GET", "HEAD"])) return;
266
358
  if (fenceRefused(ctx, req, res)) return;
267
359
  return hdsl.read().then((profile) => {
268
- if (typeof profile.skinFile !== "string" || !existsSync(profile.skinFile)) {
360
+ if (typeof profile.skinFile !== "string" || !existsSync2(profile.skinFile)) {
269
361
  res.writeHead(404, { "cache-control": "no-store" });
270
362
  res.end();
271
363
  return;
272
364
  }
273
- const body = readFileSync(profile.skinFile);
365
+ const body = readFileSync2(profile.skinFile);
274
366
  res.writeHead(200, {
275
367
  "content-type": "image/png",
276
368
  "content-length": String(body.byteLength),
@@ -346,7 +438,7 @@ function registerRoutes(ctx, scope) {
346
438
  }
347
439
  }
348
440
  };
349
- }, "dsh-claude-style: host routes");
441
+ }, `${PACKAGE_NAME}: host routes`);
350
442
  }
351
443
  export {
352
444
  registerRoutes
@@ -1,6 +1,48 @@
1
+ // packages/contracts/src/package.ts
2
+ var PACKAGE_NAME = "dsh-claude-style";
3
+
1
4
  // packages/host/src/search.ts
2
5
  import { cachePath, readJsonDocument, writeJsonDocument } from "./cache-file.js";
3
- import { readEvents } from "./session-events.js";
6
+
7
+ // packages/engine/node/session-events.ts
8
+ function eventsOf(events) {
9
+ return Array.isArray(events) ? events : null;
10
+ }
11
+ function unreadableLog(error) {
12
+ const failure = error;
13
+ return failure?.code === "SESSION_QUERY_CORRUPT_SESSION" || failure?.code === "SESSION_QUERY_SESSION_NOT_FOUND" ? failure : null;
14
+ }
15
+ function reportUnreadable(ctx, packageName, error, sessionId, label) {
16
+ ctx.logger?.warn?.(`${packageName}: session ${sessionId} left out of ${label}: ${unreadableLog(error)?.message}`);
17
+ }
18
+ function releaseObservation(observation) {
19
+ const named = observation.dispose;
20
+ if (typeof named === "function") named.call(observation);
21
+ else if (Symbol.dispose in observation) observation[Symbol.dispose]();
22
+ }
23
+ async function readEvents(ctx, packageName, sessionId, label) {
24
+ const query = ctx.get("sessionQuery");
25
+ if (query === null || query === void 0) return null;
26
+ try {
27
+ if (typeof query.observeSession === "function") {
28
+ const observation = await query.observeSession(sessionId, { projectionMode: "none" });
29
+ try {
30
+ return eventsOf(observation.events);
31
+ } finally {
32
+ releaseObservation(observation);
33
+ }
34
+ }
35
+ if (typeof query.readSession !== "function") return null;
36
+ const snapshot = await query.readSession(sessionId);
37
+ return eventsOf(snapshot?.events);
38
+ } catch (error) {
39
+ if (unreadableLog(error) === null) throw error;
40
+ reportUnreadable(ctx, packageName, error, sessionId, label);
41
+ return null;
42
+ }
43
+ }
44
+
45
+ // packages/host/src/search.ts
4
46
  var READ_CONCURRENCY = 4;
5
47
  var SESSION_LIMIT = 40;
6
48
  var SNIPPET_LEAD = 36;
@@ -98,7 +140,7 @@ function createSessionSearch(ctx) {
98
140
  writeJsonDocument(ctx, cacheFile(sessionId), "session search cache", null);
99
141
  }
100
142
  async function rebuild(sessionId, revision) {
101
- const events = await readEvents(ctx, sessionId, "content search");
143
+ const events = await readEvents(ctx, PACKAGE_NAME, sessionId, "content search");
102
144
  const messages = events === null ? [] : messagesOf(events);
103
145
  const last = events === null ? void 0 : events[events.length - 1];
104
146
  const lastSeq = typeof last?.seq === "number" ? last.seq + 1 : 0;