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.
- package/CHANGELOG.md +62 -0
- package/LICENSE +3 -2
- package/README.en.md +1 -0
- package/README.md +6 -0
- package/THIRD_PARTY_NOTICES.md +2 -0
- package/docs/FEATURES.en.md +4 -3
- package/docs/FEATURES.md +4 -3
- package/docs/SETTINGS.en.md +12 -6
- package/docs/SETTINGS.md +12 -6
- package/docs/STYLE.md +40 -1
- package/lib/assets/0443f196403b.js.br +0 -0
- package/lib/assets/39f1a2e69bb7.js.br +0 -0
- package/lib/assets/4d55814bc60a.js.br +0 -0
- package/lib/assets/6c257991027d.js.br +0 -0
- package/lib/assets/9abad5da303e.js.br +0 -0
- package/lib/assets/b55a1acf34e0.js.br +0 -0
- package/lib/assets/d2064c247435.js.br +0 -0
- package/lib/assets/manifest.json +28 -28
- package/lib/client.js +37 -11
- package/lib/host/brand.js +70 -1
- package/lib/host/cache-file.js +63 -25
- package/lib/host/harness-home.js +7 -3
- package/lib/host/index.js +4 -1
- package/lib/host/package-root.js +15 -13
- package/lib/host/peakrate.js +7 -4
- package/lib/host/routes.js +164 -72
- package/lib/host/search.js +44 -2
- package/lib/host/settings.js +137 -43
- package/lib/host/usage-record.js +5 -2
- package/lib/host/usage.js +57 -5
- package/lib/model-descriptions.json +0 -1322
- package/package.json +1 -1
- package/lib/assets/1cefeb3d67c7.js.br +0 -0
- package/lib/assets/1da1959a3cb1.js.br +0 -0
- package/lib/assets/2c3bd0b6c22c.js.br +0 -0
- package/lib/assets/34d559377558.js.br +0 -0
- package/lib/assets/acf9cf79c43e.js.br +0 -0
- package/lib/assets/b7ec75cf39a7.js.br +0 -0
- package/lib/assets/dab5fb383802.js.br +0 -0
- package/lib/host/http.js +0 -74
- 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
|
-
|
|
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",
|
package/lib/host/cache-file.js
CHANGED
|
@@ -1,31 +1,69 @@
|
|
|
1
|
-
// packages/
|
|
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
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
}
|
|
8
|
-
function
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
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
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
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,
|
package/lib/host/harness-home.js
CHANGED
|
@@ -1,4 +1,7 @@
|
|
|
1
|
-
// packages/
|
|
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,
|
|
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 =
|
|
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);
|
package/lib/host/package-root.js
CHANGED
|
@@ -1,24 +1,26 @@
|
|
|
1
|
-
// packages/
|
|
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
|
-
|
|
6
|
-
|
|
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(
|
|
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
|
package/lib/host/peakrate.js
CHANGED
|
@@ -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(
|
|
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(
|
|
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(
|
|
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(
|
|
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;
|
package/lib/host/routes.js
CHANGED
|
@@ -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
|
-
|
|
21
|
-
|
|
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 =
|
|
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 =
|
|
112
|
-
const fontsDir =
|
|
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 =
|
|
115
|
-
const
|
|
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?.(
|
|
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 =
|
|
215
|
-
sendFile(res, req.method ?? "GET",
|
|
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" || !
|
|
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 =
|
|
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
|
-
},
|
|
441
|
+
}, `${PACKAGE_NAME}: host routes`);
|
|
350
442
|
}
|
|
351
443
|
export {
|
|
352
444
|
registerRoutes
|
package/lib/host/search.js
CHANGED
|
@@ -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
|
-
|
|
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;
|