austere-axi 0.7.0 → 0.7.3
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 +22 -13
- package/dist/austere.js +106 -88
- package/dist/catalog.json +1 -1
- package/dist/chrome/chrome.css +1 -1
- package/dist/chrome/chrome.js +3 -3
- package/dist/cli.mjs +413 -210
- package/dist/packs/mermaid/catalog.json +4 -4
- package/dist/packs/mermaid/pack.js +20 -4
- package/dist/packs/shadcn/catalog.json +2 -2
- package/dist/packs/shadcn/pack.js +1 -1
- package/dist/prompt.md +1 -1
- package/package.json +1 -1
package/dist/cli.mjs
CHANGED
|
@@ -618,7 +618,7 @@ var init_paths = __esm({
|
|
|
618
618
|
HERE = path.dirname(fileURLToPath(import.meta.url));
|
|
619
619
|
BUNDLED = true;
|
|
620
620
|
ASSET_DIR = BUNDLED ? HERE : path.resolve(HERE, "../../dist");
|
|
621
|
-
VERSION = true ? "0.7.
|
|
621
|
+
VERSION = true ? "0.7.3" : packageVersion();
|
|
622
622
|
CLI_ENTRY = BUNDLED ? fileURLToPath(import.meta.url) : path.resolve(HERE, "main.ts");
|
|
623
623
|
securedDir = null;
|
|
624
624
|
}
|
|
@@ -1907,38 +1907,177 @@ var init_sessions = __esm({
|
|
|
1907
1907
|
}
|
|
1908
1908
|
});
|
|
1909
1909
|
|
|
1910
|
-
// src/cli/
|
|
1910
|
+
// src/cli/assets.ts
|
|
1911
1911
|
import fs9 from "node:fs";
|
|
1912
1912
|
import path8 from "node:path";
|
|
1913
|
+
function resolveSibling(dir, rel, maxBytes = MAX_ASSET_BYTES) {
|
|
1914
|
+
if (rel.includes("\0")) return { ok: false, reason: "outside" };
|
|
1915
|
+
const file3 = path8.resolve(dir, rel);
|
|
1916
|
+
if (!file3.startsWith(dir + path8.sep)) return { ok: false, reason: "outside" };
|
|
1917
|
+
if (rel.split(/[/\\]/).some((p) => p !== "." && p.startsWith("."))) return { ok: false, reason: "hidden" };
|
|
1918
|
+
try {
|
|
1919
|
+
const realDir = fs9.realpathSync(dir);
|
|
1920
|
+
const real = fs9.realpathSync(file3);
|
|
1921
|
+
if (!real.startsWith(realDir + path8.sep)) return { ok: false, reason: "outside" };
|
|
1922
|
+
if (path8.relative(realDir, real).split(path8.sep).some((p) => p.startsWith("."))) return { ok: false, reason: "hidden" };
|
|
1923
|
+
const st2 = fs9.statSync(real);
|
|
1924
|
+
if (!st2.isFile()) return { ok: false, reason: "missing" };
|
|
1925
|
+
if (st2.size > maxBytes) return { ok: false, reason: "too-large" };
|
|
1926
|
+
return { ok: true, file: real, size: st2.size };
|
|
1927
|
+
} catch {
|
|
1928
|
+
return { ok: false, reason: "missing" };
|
|
1929
|
+
}
|
|
1930
|
+
}
|
|
1931
|
+
var MAX_ASSET_BYTES;
|
|
1932
|
+
var init_assets = __esm({
|
|
1933
|
+
"src/cli/assets.ts"() {
|
|
1934
|
+
"use strict";
|
|
1935
|
+
MAX_ASSET_BYTES = 64 * 1024 * 1024;
|
|
1936
|
+
}
|
|
1937
|
+
});
|
|
1938
|
+
|
|
1939
|
+
// src/cli/export.ts
|
|
1940
|
+
import fs10 from "node:fs";
|
|
1941
|
+
import path9 from "node:path";
|
|
1913
1942
|
function inlineScript(code) {
|
|
1914
1943
|
return `<script>${code.replace(/<\/script/gi, "<\\/script")}</script>`;
|
|
1915
1944
|
}
|
|
1916
|
-
function
|
|
1945
|
+
function stringAt(src, i) {
|
|
1946
|
+
const q2 = src[i];
|
|
1947
|
+
let value = "";
|
|
1948
|
+
for (let j = i + 1; j < src.length; j++) {
|
|
1949
|
+
const c = src[j];
|
|
1950
|
+
if (c === "\\" && j + 1 < src.length) value += src[++j];
|
|
1951
|
+
else if (c === q2) return { start: i, end: j + 1, value };
|
|
1952
|
+
else value += c;
|
|
1953
|
+
}
|
|
1954
|
+
return null;
|
|
1955
|
+
}
|
|
1956
|
+
function skipBlank(src, i) {
|
|
1957
|
+
for (; ; ) {
|
|
1958
|
+
while (i < src.length && /\s/.test(src[i])) i++;
|
|
1959
|
+
if (src[i] === "#" || src[i] === "/" && src[i + 1] === "/") while (i < src.length && src[i] !== "\n") i++;
|
|
1960
|
+
else return i;
|
|
1961
|
+
}
|
|
1962
|
+
}
|
|
1963
|
+
function imageSources(src) {
|
|
1964
|
+
const out = [];
|
|
1965
|
+
let i = 0;
|
|
1966
|
+
while (i < src.length) {
|
|
1967
|
+
const c = src[i];
|
|
1968
|
+
if (c === '"' || c === "'") {
|
|
1969
|
+
i = stringAt(src, i)?.end ?? src.length;
|
|
1970
|
+
} else if (c === "#" || c === "/" && src[i + 1] === "/") {
|
|
1971
|
+
while (i < src.length && src[i] !== "\n") i++;
|
|
1972
|
+
} else if (/[A-Za-z_$]/.test(c)) {
|
|
1973
|
+
let j = i + 1;
|
|
1974
|
+
while (j < src.length && /[\w$]/.test(src[j])) j++;
|
|
1975
|
+
const word = src.slice(i, j);
|
|
1976
|
+
i = j;
|
|
1977
|
+
if (word !== "Image") continue;
|
|
1978
|
+
j = skipBlank(src, j);
|
|
1979
|
+
if (src[j] !== "(") continue;
|
|
1980
|
+
let k = j + 1;
|
|
1981
|
+
let depth = 0;
|
|
1982
|
+
while (k < src.length) {
|
|
1983
|
+
const d = src[k];
|
|
1984
|
+
if (d === '"' || d === "'") k = stringAt(src, k)?.end ?? src.length;
|
|
1985
|
+
else if (d === "#" || d === "/" && src[k + 1] === "/") k = skipBlank(src, k);
|
|
1986
|
+
else if (d === "(" || d === "[" || d === "{") {
|
|
1987
|
+
depth++;
|
|
1988
|
+
k++;
|
|
1989
|
+
} else if (d === ")" || d === "]" || d === "}") {
|
|
1990
|
+
if (depth === 0) break;
|
|
1991
|
+
depth--;
|
|
1992
|
+
k++;
|
|
1993
|
+
} else if (d === "," && depth === 0) break;
|
|
1994
|
+
else k++;
|
|
1995
|
+
}
|
|
1996
|
+
if (src[k] !== ",") continue;
|
|
1997
|
+
k = skipBlank(src, k + 1);
|
|
1998
|
+
if (src[k] === '"' || src[k] === "'") {
|
|
1999
|
+
const lit = stringAt(src, k);
|
|
2000
|
+
if (lit) out.push(lit);
|
|
2001
|
+
}
|
|
2002
|
+
} else i++;
|
|
2003
|
+
}
|
|
2004
|
+
return out;
|
|
2005
|
+
}
|
|
2006
|
+
function inlineImages(program, dir, notices) {
|
|
2007
|
+
let out = "";
|
|
2008
|
+
let at2 = 0;
|
|
2009
|
+
const seen = /* @__PURE__ */ new Set();
|
|
2010
|
+
const warn = (src, why) => {
|
|
2011
|
+
if (!seen.has(src)) notices.push(`Image "${src}" is not inlined: ${why}. Keep it next to the exported file.`);
|
|
2012
|
+
seen.add(src);
|
|
2013
|
+
};
|
|
2014
|
+
for (const lit of imageSources(program)) {
|
|
2015
|
+
if (/^(?:[a-z][a-z0-9+.-]*:|\/\/)/i.test(lit.value)) continue;
|
|
2016
|
+
let rel = lit.value.replace(/[?#].*$/, "");
|
|
2017
|
+
try {
|
|
2018
|
+
rel = decodeURIComponent(rel);
|
|
2019
|
+
} catch {
|
|
2020
|
+
}
|
|
2021
|
+
const type = IMAGE_TYPES[path9.extname(rel).toLowerCase()];
|
|
2022
|
+
if (!type) {
|
|
2023
|
+
warn(lit.value, "not a png, jpg, gif, webp, svg or avif file");
|
|
2024
|
+
continue;
|
|
2025
|
+
}
|
|
2026
|
+
const sib = resolveSibling(dir, rel, MAX_INLINE_BYTES);
|
|
2027
|
+
if (!sib.ok) {
|
|
2028
|
+
const why = { missing: "no such file next to the page", outside: "it is outside the page's folder", hidden: "hidden files are never read", "too-large": "it is over 10 MB" }[sib.reason];
|
|
2029
|
+
warn(lit.value, why);
|
|
2030
|
+
continue;
|
|
2031
|
+
}
|
|
2032
|
+
let bytes;
|
|
2033
|
+
try {
|
|
2034
|
+
bytes = fs10.readFileSync(sib.file);
|
|
2035
|
+
} catch {
|
|
2036
|
+
warn(lit.value, "it cannot be read (permissions?)");
|
|
2037
|
+
continue;
|
|
2038
|
+
}
|
|
2039
|
+
out += program.slice(at2, lit.start) + JSON.stringify(`data:${type};base64,${bytes.toString("base64")}`);
|
|
2040
|
+
at2 = lit.end;
|
|
2041
|
+
}
|
|
2042
|
+
return out + program.slice(at2);
|
|
2043
|
+
}
|
|
2044
|
+
function exportHtml(html, dir) {
|
|
1917
2045
|
const art = readArtifact(html);
|
|
1918
2046
|
const notices = [];
|
|
1919
2047
|
if (art.program == null) throw new Error('no <script type="text/openui"> block');
|
|
1920
2048
|
let tags = "";
|
|
1921
2049
|
if (/\bMermaid\s*\(/.test(art.program)) {
|
|
1922
|
-
tags += inlineScript(
|
|
2050
|
+
tags += inlineScript(fs10.readFileSync(assetPath("mermaid.min.js"), "utf8")) + "\n";
|
|
1923
2051
|
}
|
|
1924
|
-
tags += inlineScript(
|
|
1925
|
-
for (const p of implicitPacks(art.program)) tags += "\n" + inlineScript(
|
|
2052
|
+
tags += inlineScript(fs10.readFileSync(assetPath("austere.js"), "utf8"));
|
|
2053
|
+
for (const p of implicitPacks(art.program)) tags += "\n" + inlineScript(fs10.readFileSync(path9.join(p.dir, "pack.js"), "utf8"));
|
|
1926
2054
|
const packs = pagePacks(html);
|
|
1927
|
-
for (const p of packs.installed) tags += "\n" + inlineScript(
|
|
2055
|
+
for (const p of packs.installed) tags += "\n" + inlineScript(fs10.readFileSync(path9.join(p.dir, "pack.js"), "utf8"));
|
|
1928
2056
|
for (const p of [...packs.missing, ...packs.mismatched]) {
|
|
1929
2057
|
notices.push(`Pack ${p.name}@${p.version} is not installed here, so the exported page loads it from the CDN (needs network).`);
|
|
1930
2058
|
}
|
|
1931
|
-
const
|
|
1932
|
-
const
|
|
1933
|
-
|
|
1934
|
-
return { html: out, notices };
|
|
2059
|
+
const inlined = inlineImages(art.program, dir, notices);
|
|
2060
|
+
const withImages = inlined === art.program ? html : html.slice(0, art.programStart) + inlined + html.slice(art.programEnd);
|
|
2061
|
+
return { html: rewriteRuntime(withImages, () => tags), notices };
|
|
1935
2062
|
}
|
|
2063
|
+
var IMAGE_TYPES, MAX_INLINE_BYTES;
|
|
1936
2064
|
var init_export = __esm({
|
|
1937
2065
|
"src/cli/export.ts"() {
|
|
1938
2066
|
"use strict";
|
|
1939
2067
|
init_artifact();
|
|
2068
|
+
init_assets();
|
|
1940
2069
|
init_paths();
|
|
1941
2070
|
init_packs();
|
|
2071
|
+
IMAGE_TYPES = {
|
|
2072
|
+
".png": "image/png",
|
|
2073
|
+
".jpg": "image/jpeg",
|
|
2074
|
+
".jpeg": "image/jpeg",
|
|
2075
|
+
".gif": "image/gif",
|
|
2076
|
+
".webp": "image/webp",
|
|
2077
|
+
".svg": "image/svg+xml",
|
|
2078
|
+
".avif": "image/avif"
|
|
2079
|
+
};
|
|
2080
|
+
MAX_INLINE_BYTES = 10 * 1024 * 1024;
|
|
1942
2081
|
}
|
|
1943
2082
|
});
|
|
1944
2083
|
|
|
@@ -1953,8 +2092,8 @@ __export(install_exports, {
|
|
|
1953
2092
|
removePack: () => removePack,
|
|
1954
2093
|
untar: () => untar
|
|
1955
2094
|
});
|
|
1956
|
-
import
|
|
1957
|
-
import
|
|
2095
|
+
import fs12 from "node:fs";
|
|
2096
|
+
import path11 from "node:path";
|
|
1958
2097
|
import zlib from "node:zlib";
|
|
1959
2098
|
import crypto4 from "node:crypto";
|
|
1960
2099
|
function registryUrl() {
|
|
@@ -2091,15 +2230,15 @@ function readTarball(tgz, label) {
|
|
|
2091
2230
|
return { packJs, catalog, packageJson: files.get("package.json") || null };
|
|
2092
2231
|
}
|
|
2093
2232
|
function fromTarball(file3) {
|
|
2094
|
-
const abs =
|
|
2095
|
-
if (!
|
|
2096
|
-
return { ...readTarball(
|
|
2233
|
+
const abs = path11.resolve(file3.replace(/^~(?=[\\/])/, process.env.HOME || ""));
|
|
2234
|
+
if (!fs12.existsSync(abs)) throw new Error(`no such file: ${abs}`);
|
|
2235
|
+
return { ...readTarball(fs12.readFileSync(abs), path11.basename(abs)), source: "tarball", resolved: abs };
|
|
2097
2236
|
}
|
|
2098
2237
|
function fromFolder(dir) {
|
|
2099
|
-
const abs =
|
|
2100
|
-
if (!
|
|
2101
|
-
if (
|
|
2102
|
-
const read = (rel) =>
|
|
2238
|
+
const abs = path11.resolve(dir.replace(/^~(?=[\\/])/, process.env.HOME || ""));
|
|
2239
|
+
if (!fs12.existsSync(abs)) throw new Error(`no such folder: ${abs}`);
|
|
2240
|
+
if (fs12.statSync(abs).isFile()) return fromTarball(abs);
|
|
2241
|
+
const read = (rel) => fs12.existsSync(path11.join(abs, rel)) ? fs12.readFileSync(path11.join(abs, rel)) : null;
|
|
2103
2242
|
const packJs = read("dist/pack.js");
|
|
2104
2243
|
const catalog = read("dist/catalog.json");
|
|
2105
2244
|
if (!packJs || !catalog) throw new Error(`${abs} has no dist/pack.js and dist/catalog.json: run \`austere-axi components build ${dir}\` first`);
|
|
@@ -2139,10 +2278,10 @@ async function addPack(spec, { trust = false } = {}) {
|
|
|
2139
2278
|
}
|
|
2140
2279
|
const got = local ? fromFolder(spec) : await fromRegistry(spec);
|
|
2141
2280
|
if (got.source === "tarball" && !trust) {
|
|
2142
|
-
const peek = parseCatalog(got.catalog,
|
|
2281
|
+
const peek = parseCatalog(got.catalog, path11.basename(got.resolved));
|
|
2143
2282
|
throw Object.assign(
|
|
2144
2283
|
new Error(
|
|
2145
|
-
`${
|
|
2284
|
+
`${path11.basename(got.resolved)} (${peek.pack}) comes from a file, not the registry: its code would run inside your review pages. Rerun with --trust once you have looked at it.`
|
|
2146
2285
|
),
|
|
2147
2286
|
{ code: "untrusted" }
|
|
2148
2287
|
);
|
|
@@ -2167,14 +2306,14 @@ async function addPack(spec, { trust = false } = {}) {
|
|
|
2167
2306
|
}
|
|
2168
2307
|
const lock = readLock();
|
|
2169
2308
|
const previous = lock.packs[cat.pack];
|
|
2170
|
-
const dir =
|
|
2171
|
-
|
|
2172
|
-
|
|
2173
|
-
|
|
2174
|
-
|
|
2175
|
-
if (got.packageJson)
|
|
2309
|
+
const dir = path11.join(packsDir(), packDirName(cat.pack, cat.version));
|
|
2310
|
+
fs12.rmSync(dir, { recursive: true, force: true });
|
|
2311
|
+
fs12.mkdirSync(dir, { recursive: true });
|
|
2312
|
+
fs12.writeFileSync(path11.join(dir, "pack.js"), got.packJs);
|
|
2313
|
+
fs12.writeFileSync(path11.join(dir, "catalog.json"), got.catalog);
|
|
2314
|
+
if (got.packageJson) fs12.writeFileSync(path11.join(dir, "package.json"), got.packageJson);
|
|
2176
2315
|
if (previous && previous.version !== cat.version) {
|
|
2177
|
-
|
|
2316
|
+
fs12.rmSync(path11.join(packsDir(), packDirName(cat.pack, previous.version)), { recursive: true, force: true });
|
|
2178
2317
|
}
|
|
2179
2318
|
lock.packs[cat.pack] = {
|
|
2180
2319
|
version: cat.version,
|
|
@@ -2194,7 +2333,7 @@ function removePack(name) {
|
|
|
2194
2333
|
if (!entry) return null;
|
|
2195
2334
|
delete lock.packs[name];
|
|
2196
2335
|
writeLock(lock);
|
|
2197
|
-
|
|
2336
|
+
fs12.rmSync(path11.join(packsDir(), packDirName(name, entry.version)), { recursive: true, force: true });
|
|
2198
2337
|
return { name, version: entry.version };
|
|
2199
2338
|
}
|
|
2200
2339
|
var MAX_TARBALL, MAX_PACK_JS;
|
|
@@ -2215,8 +2354,8 @@ __export(pack_dev_exports, {
|
|
|
2215
2354
|
buildPackDir: () => buildPackDir,
|
|
2216
2355
|
newPack: () => newPack
|
|
2217
2356
|
});
|
|
2218
|
-
import
|
|
2219
|
-
import
|
|
2357
|
+
import fs13 from "node:fs";
|
|
2358
|
+
import path12 from "node:path";
|
|
2220
2359
|
import { createRequire } from "node:module";
|
|
2221
2360
|
import { pathToFileURL } from "node:url";
|
|
2222
2361
|
function packageJson(name) {
|
|
@@ -2253,9 +2392,9 @@ Publish with \`npm publish\` after \`npm run build\`. Others install it with
|
|
|
2253
2392
|
}
|
|
2254
2393
|
function newPack(dir, { name } = {}) {
|
|
2255
2394
|
if (!dir) throw new Error("new needs a folder: austere-axi components new austere-pack-milestones");
|
|
2256
|
-
const abs =
|
|
2257
|
-
if (
|
|
2258
|
-
const pkgName = name ||
|
|
2395
|
+
const abs = path12.resolve(dir);
|
|
2396
|
+
if (fs13.existsSync(abs) && fs13.readdirSync(abs).length) throw new Error(`${abs} is not empty`);
|
|
2397
|
+
const pkgName = name || path12.basename(abs).toLowerCase().replace(/[^a-z0-9._-]+/g, "-");
|
|
2259
2398
|
if (!isValidPackName(pkgName)) throw new Error(`${JSON.stringify(pkgName)} is not an npm package name; pass --name`);
|
|
2260
2399
|
const files = {
|
|
2261
2400
|
"package.json": JSON.stringify(packageJson(pkgName), null, 2) + "\n",
|
|
@@ -2264,13 +2403,13 @@ function newPack(dir, { name } = {}) {
|
|
|
2264
2403
|
...TEMPLATE
|
|
2265
2404
|
};
|
|
2266
2405
|
for (const [rel, text] of Object.entries(files)) {
|
|
2267
|
-
|
|
2268
|
-
|
|
2406
|
+
fs13.mkdirSync(path12.dirname(path12.join(abs, rel)), { recursive: true });
|
|
2407
|
+
fs13.writeFileSync(path12.join(abs, rel), text);
|
|
2269
2408
|
}
|
|
2270
2409
|
return { dir: abs, name: pkgName, files: Object.keys(files) };
|
|
2271
2410
|
}
|
|
2272
2411
|
async function findEsbuild(dir) {
|
|
2273
|
-
for (const base of [
|
|
2412
|
+
for (const base of [path12.join(dir, "package.json"), path12.join(process.cwd(), "package.json"), import.meta.url]) {
|
|
2274
2413
|
try {
|
|
2275
2414
|
const resolved = createRequire(base).resolve("esbuild");
|
|
2276
2415
|
const esbuild = await import(pathToFileURL(resolved).href);
|
|
@@ -2281,8 +2420,8 @@ async function findEsbuild(dir) {
|
|
|
2281
2420
|
return null;
|
|
2282
2421
|
}
|
|
2283
2422
|
async function buildPackDir(dir = ".") {
|
|
2284
|
-
const abs =
|
|
2285
|
-
if (!
|
|
2423
|
+
const abs = path12.resolve(dir);
|
|
2424
|
+
if (!fs13.existsSync(path12.join(abs, "package.json"))) throw new Error(`${abs} has no package.json (\`austere-axi components new <dir>\` makes a pack)`);
|
|
2286
2425
|
const esbuild = await findEsbuild(abs);
|
|
2287
2426
|
if (!esbuild) throw new Error(`components build needs esbuild: run \`npm install -D esbuild\` in ${abs}`);
|
|
2288
2427
|
process.env.OPENUI_TELEMETRY_DISABLED ||= "1";
|
|
@@ -2406,7 +2545,7 @@ export default austereComponent({
|
|
|
2406
2545
|
|
|
2407
2546
|
// src/cli/net.ts
|
|
2408
2547
|
import { execFile } from "node:child_process";
|
|
2409
|
-
import
|
|
2548
|
+
import fs14 from "node:fs";
|
|
2410
2549
|
function run(bin, args) {
|
|
2411
2550
|
return new Promise((resolve) => {
|
|
2412
2551
|
execFile(bin, args, { timeout: 2500, windowsHide: true }, (err, stdout) => resolve(err ? null : stdout));
|
|
@@ -2417,7 +2556,7 @@ async function detectTailscale({ fresh = false } = {}) {
|
|
|
2417
2556
|
if (!fresh && Date.now() - cache.at < 3e4) return cache.value;
|
|
2418
2557
|
let value = null;
|
|
2419
2558
|
for (const bin of CANDIDATES) {
|
|
2420
|
-
if (bin.startsWith("/") && !
|
|
2559
|
+
if (bin.startsWith("/") && !fs14.existsSync(bin)) continue;
|
|
2421
2560
|
const out = await run(bin, ["status", "--json"]);
|
|
2422
2561
|
if (!out) continue;
|
|
2423
2562
|
try {
|
|
@@ -2515,7 +2654,7 @@ var init_items = __esm({
|
|
|
2515
2654
|
|
|
2516
2655
|
// src/cli/hub-page.ts
|
|
2517
2656
|
import os3 from "node:os";
|
|
2518
|
-
import
|
|
2657
|
+
import path13 from "node:path";
|
|
2519
2658
|
function day(ms) {
|
|
2520
2659
|
const d = new Date(ms);
|
|
2521
2660
|
const today = /* @__PURE__ */ new Date();
|
|
@@ -2530,7 +2669,7 @@ function time3(ms) {
|
|
|
2530
2669
|
}
|
|
2531
2670
|
function tilde(p) {
|
|
2532
2671
|
const home = os3.homedir();
|
|
2533
|
-
return p === home || p.startsWith(home +
|
|
2672
|
+
return p === home || p.startsWith(home + path13.sep) ? "~" + p.slice(home.length) : p;
|
|
2534
2673
|
}
|
|
2535
2674
|
function counts(a) {
|
|
2536
2675
|
const waiting = a.open + a.received;
|
|
@@ -2566,13 +2705,13 @@ function hubPage(rows, { version: version2, q: q2, project, stats }) {
|
|
|
2566
2705
|
const body = [...days.entries()].map(
|
|
2567
2706
|
([d, items]) => `<h3>${escapeHtml(d)}</h3><ul>${items.map(
|
|
2568
2707
|
(a) => `<li><a href="/hub/open/${a.id}" title="${escapeHtml(a.file)}">
|
|
2569
|
-
<strong>${escapeHtml(a.title ||
|
|
2570
|
-
<span class="meta">${escapeHtml(
|
|
2708
|
+
<strong>${escapeHtml(a.title || path13.basename(a.file))}</strong>
|
|
2709
|
+
<span class="meta">${escapeHtml(path13.relative(proj, a.file) || path13.basename(a.file))} \xB7 ${time3(a.updated_at)} \xB7 ${state(a)}${counts(a) ? ` \xB7 ${counts(a)}` : ""}</span>
|
|
2571
2710
|
</a></li>`
|
|
2572
2711
|
).join("")}</ul>`
|
|
2573
2712
|
).join("");
|
|
2574
2713
|
const unanswered = list.reduce((n, a) => n + a.open + a.received, 0);
|
|
2575
|
-
return `<section><h2><a href="/?project=${encodeURIComponent(proj)}">${escapeHtml(
|
|
2714
|
+
return `<section><h2><a href="/?project=${encodeURIComponent(proj)}">${escapeHtml(path13.basename(proj) || proj)}</a> <small title="${escapeHtml(proj)}">${escapeHtml(
|
|
2576
2715
|
shortPath(proj)
|
|
2577
2716
|
)}</small>${unanswered ? ` <b class="open">${unanswered} unanswered</b>` : ""}</h2>${body}</section>`;
|
|
2578
2717
|
}).join("");
|
|
@@ -2595,7 +2734,7 @@ function notesPage(rows, { version: version2, q: q2, project, status, author = "
|
|
|
2595
2734
|
const when = `${day(n.at)} ${time3(n.at)}`;
|
|
2596
2735
|
return `<li class="n"><a href="/hub/open/${escapeHtml(n.artifact_id)}" title="${escapeHtml(n.file)}">
|
|
2597
2736
|
<p class="note">${escapeHtml(n.text || "(no text)")}</p>
|
|
2598
|
-
<span class="note-t">${n.author ? `<b class="by">${escapeHtml(n.author)}</b> \xB7 ` : ""}${n.target ? `on ${escapeHtml(n.target)} \xB7 ` : ""}<strong>${escapeHtml(n.title ||
|
|
2737
|
+
<span class="note-t">${n.author ? `<b class="by">${escapeHtml(n.author)}</b> \xB7 ` : ""}${n.target ? `on ${escapeHtml(n.target)} \xB7 ` : ""}<strong>${escapeHtml(n.title || path13.basename(n.file))}</strong> \xB7 ${escapeHtml(path13.basename(n.project) || n.project)} \xB7 ${escapeHtml(when)} \xB7 <span class="st ${waiting ? "waiting" : "done"}">${STATUS_LABEL[n.status] || escapeHtml(n.status)}</span></span>
|
|
2599
2738
|
</a></li>`;
|
|
2600
2739
|
}).join("");
|
|
2601
2740
|
const opt = (v, label) => `<option value="${v}"${status === v ? " selected" : ""}>${label}</option>`;
|
|
@@ -2650,9 +2789,9 @@ __export(server_exports, {
|
|
|
2650
2789
|
persistEnv: () => persistEnv,
|
|
2651
2790
|
runServer: () => runServer
|
|
2652
2791
|
});
|
|
2653
|
-
import
|
|
2792
|
+
import fs15 from "node:fs";
|
|
2654
2793
|
import http3 from "node:http";
|
|
2655
|
-
import
|
|
2794
|
+
import path14 from "node:path";
|
|
2656
2795
|
import crypto5 from "node:crypto";
|
|
2657
2796
|
function persistEnv() {
|
|
2658
2797
|
return /^(1|true|yes)$/i.test(process.env.AUSTERE_AXI_PERSIST || "");
|
|
@@ -2667,7 +2806,7 @@ async function runServer({
|
|
|
2667
2806
|
const line = `${(/* @__PURE__ */ new Date()).toISOString()} ${a.join(" ")}`;
|
|
2668
2807
|
if (verbose) process.stderr.write(line + "\n");
|
|
2669
2808
|
try {
|
|
2670
|
-
|
|
2809
|
+
fs15.appendFileSync(path14.join(stateDir(), "server.log"), line + "\n", { mode: 384 });
|
|
2671
2810
|
} catch {
|
|
2672
2811
|
}
|
|
2673
2812
|
};
|
|
@@ -2849,7 +2988,7 @@ data: ${JSON.stringify({ state: "revoked" })}
|
|
|
2849
2988
|
}
|
|
2850
2989
|
function readFileSafe(file3) {
|
|
2851
2990
|
try {
|
|
2852
|
-
return
|
|
2991
|
+
return fs15.readFileSync(file3, "utf8");
|
|
2853
2992
|
} catch {
|
|
2854
2993
|
return null;
|
|
2855
2994
|
}
|
|
@@ -2861,14 +3000,14 @@ data: ${JSON.stringify({ state: "revoked" })}
|
|
|
2861
3000
|
const w = { html, program: art?.program ?? null, shell: art?.shell ?? null, timer: void 0 };
|
|
2862
3001
|
watchers.set(s.id, w);
|
|
2863
3002
|
if (art?.title) s.title = art.title;
|
|
2864
|
-
|
|
3003
|
+
fs15.watchFile(s.file, { interval: 300 }, () => {
|
|
2865
3004
|
clearTimeout(w.timer);
|
|
2866
3005
|
w.timer = setTimeout(() => onFileChange(s, w), 120);
|
|
2867
3006
|
});
|
|
2868
3007
|
}
|
|
2869
3008
|
function unwatch(id) {
|
|
2870
3009
|
const s = store.get(id);
|
|
2871
|
-
if (s)
|
|
3010
|
+
if (s) fs15.unwatchFile(s.file);
|
|
2872
3011
|
watchers.delete(id);
|
|
2873
3012
|
}
|
|
2874
3013
|
function onFileChange(s, w) {
|
|
@@ -3045,7 +3184,7 @@ data: ${JSON.stringify({ state: "revoked" })}
|
|
|
3045
3184
|
const file3 = typeof body.file === "string" ? body.file : "";
|
|
3046
3185
|
if (!file3) return send(res, 400, { error: "file is required" });
|
|
3047
3186
|
if (route === "share") {
|
|
3048
|
-
if (!
|
|
3187
|
+
if (!fs15.existsSync(file3)) return send(res, 404, { error: `no such file: ${file3}` });
|
|
3049
3188
|
await ensureTailnetListener();
|
|
3050
3189
|
if (!remoteBase()) {
|
|
3051
3190
|
return send(res, 409, {
|
|
@@ -3065,7 +3204,7 @@ data: ${JSON.stringify({ state: "revoked" })}
|
|
|
3065
3204
|
return send(res, 200, { id: inviteId(inv), name: inv.name, auto: inv.auto, link: inviteLink(inv), file: inv.file });
|
|
3066
3205
|
}
|
|
3067
3206
|
if (route === "open") {
|
|
3068
|
-
if (!
|
|
3207
|
+
if (!fs15.existsSync(file3)) return send(res, 404, { error: `no such file: ${file3}` });
|
|
3069
3208
|
await ensureTailnetListener();
|
|
3070
3209
|
const s2 = store.ensure(file3);
|
|
3071
3210
|
if (s2.closedAt && !body.reopen) {
|
|
@@ -3198,7 +3337,7 @@ data: ${JSON.stringify({ state: "revoked" })}
|
|
|
3198
3337
|
}
|
|
3199
3338
|
const file3 = installedPackFile(spec.name, spec.version);
|
|
3200
3339
|
if (!file3) return send(res, 404, `pack ${spec.name}@${spec.version} is not installed (austere-axi components add ${spec.name}@${spec.version})`);
|
|
3201
|
-
|
|
3340
|
+
fs15.readFile(file3, (err, buf) => {
|
|
3202
3341
|
if (err) return send(res, 404, "not found");
|
|
3203
3342
|
const actual = `sha384-${crypto5.createHash("sha384").update(buf).digest("base64")}`;
|
|
3204
3343
|
const locked = readLock().packs[spec.name]?.integrity;
|
|
@@ -3222,13 +3361,13 @@ data: ${JSON.stringify({ state: "revoked" })}
|
|
|
3222
3361
|
}
|
|
3223
3362
|
function serveAsset(res, rel, url2) {
|
|
3224
3363
|
if (rel.startsWith("installed-packs/")) return serveInstalledPack(res, rel, url2);
|
|
3225
|
-
const clean =
|
|
3226
|
-
const file3 =
|
|
3227
|
-
if (!file3.startsWith(ASSET_DIR +
|
|
3228
|
-
|
|
3364
|
+
const clean = path14.normalize(rel).replace(/^(\.\.[/\\])+/, "");
|
|
3365
|
+
const file3 = path14.join(ASSET_DIR, clean);
|
|
3366
|
+
if (!file3.startsWith(ASSET_DIR + path14.sep)) return send(res, 404, "not found");
|
|
3367
|
+
fs15.stat(file3, (err, st2) => {
|
|
3229
3368
|
if (err || !st2.isFile()) return send(res, 404, "not found");
|
|
3230
3369
|
streamFile(res, file3, {
|
|
3231
|
-
"content-type": MIME[
|
|
3370
|
+
"content-type": MIME[path14.extname(file3)] || "application/octet-stream",
|
|
3232
3371
|
"content-length": st2.size,
|
|
3233
3372
|
"cache-control": "no-cache",
|
|
3234
3373
|
"x-content-type-options": "nosniff"
|
|
@@ -3237,7 +3376,7 @@ data: ${JSON.stringify({ state: "revoked" })}
|
|
|
3237
3376
|
}
|
|
3238
3377
|
const ARTIFACT_CSP = "sandbox allow-scripts allow-popups allow-popups-to-escape-sandbox allow-forms";
|
|
3239
3378
|
function streamFile(res, file3, headers) {
|
|
3240
|
-
const rs =
|
|
3379
|
+
const rs = fs15.createReadStream(file3);
|
|
3241
3380
|
rs.once("open", () => {
|
|
3242
3381
|
res.writeHead(200, headers);
|
|
3243
3382
|
rs.pipe(res);
|
|
@@ -3249,9 +3388,20 @@ data: ${JSON.stringify({ state: "revoked" })}
|
|
|
3249
3388
|
});
|
|
3250
3389
|
res.once("close", () => rs.destroy());
|
|
3251
3390
|
}
|
|
3391
|
+
function assetToken(s, viewer) {
|
|
3392
|
+
const who = viewer.role === "owner" ? "owner" : `invite:${viewer.token}`;
|
|
3393
|
+
return crypto5.createHmac("sha256", ownerToken).update(`austere-axi asset\0${s.id}\0${who}`).digest("base64url");
|
|
3394
|
+
}
|
|
3395
|
+
function assetTokenValid(s, token) {
|
|
3396
|
+
let ok2 = safeEqual(token, assetToken(s, OWNER));
|
|
3397
|
+
for (const inv of invites.list()) {
|
|
3398
|
+
if (inv.sessionId === s.id && safeEqual(token, assetToken(s, { role: "reviewer", name: inv.name, auto: inv.auto, token: inv.token }))) ok2 = true;
|
|
3399
|
+
}
|
|
3400
|
+
return ok2;
|
|
3401
|
+
}
|
|
3252
3402
|
function serveArtifact(req, res, s, rest) {
|
|
3253
|
-
const dir =
|
|
3254
|
-
const base =
|
|
3403
|
+
const dir = path14.dirname(s.file);
|
|
3404
|
+
const base = path14.basename(s.file);
|
|
3255
3405
|
if (rest === base || rest === "") {
|
|
3256
3406
|
const html = readFileSafe(s.file);
|
|
3257
3407
|
if (html == null) return send(res, 404, "artifact file is missing");
|
|
@@ -3264,27 +3414,14 @@ data: ${JSON.stringify({ state: "revoked" })}
|
|
|
3264
3414
|
} catch {
|
|
3265
3415
|
return send(res, 400, "bad path");
|
|
3266
3416
|
}
|
|
3267
|
-
|
|
3268
|
-
|
|
3269
|
-
|
|
3270
|
-
|
|
3271
|
-
|
|
3272
|
-
|
|
3273
|
-
|
|
3274
|
-
|
|
3275
|
-
if (e2 || !real.startsWith(realDir + path13.sep)) return send(res, 404, "not found");
|
|
3276
|
-
if (path13.relative(realDir, real).split(path13.sep).some((p) => p.startsWith("."))) return send(res, 404, "not found");
|
|
3277
|
-
fs14.stat(real, (err, st2) => {
|
|
3278
|
-
if (err || !st2.isFile() || st2.size > 64 * 1024 * 1024) return send(res, 404, "not found");
|
|
3279
|
-
streamFile(res, real, {
|
|
3280
|
-
"content-type": MIME[path13.extname(real).toLowerCase()] || "application/octet-stream",
|
|
3281
|
-
"content-length": st2.size,
|
|
3282
|
-
"cache-control": "no-cache",
|
|
3283
|
-
"x-content-type-options": "nosniff",
|
|
3284
|
-
"content-security-policy": ARTIFACT_CSP
|
|
3285
|
-
});
|
|
3286
|
-
});
|
|
3287
|
-
});
|
|
3417
|
+
const sib = resolveSibling(dir, decoded);
|
|
3418
|
+
if (!sib.ok) return send(res, 404, "not found");
|
|
3419
|
+
streamFile(res, sib.file, {
|
|
3420
|
+
"content-type": MIME[path14.extname(sib.file).toLowerCase()] || "application/octet-stream",
|
|
3421
|
+
"content-length": sib.size,
|
|
3422
|
+
"cache-control": "no-cache",
|
|
3423
|
+
"x-content-type-options": "nosniff",
|
|
3424
|
+
"content-security-policy": ARTIFACT_CSP
|
|
3288
3425
|
});
|
|
3289
3426
|
}
|
|
3290
3427
|
function chromePage(s, viewer) {
|
|
@@ -3293,8 +3430,8 @@ data: ${JSON.stringify({ state: "revoked" })}
|
|
|
3293
3430
|
title: s.title,
|
|
3294
3431
|
file: viewer.role === "owner" ? s.file : "",
|
|
3295
3432
|
viewer: { role: viewer.role, name: viewer.name, auto: viewer.role === "reviewer" ? viewer.auto : void 0 },
|
|
3296
|
-
name:
|
|
3297
|
-
artifactUrl: `/s/${s.id}/a/${encodeURIComponent(
|
|
3433
|
+
name: path14.basename(s.file),
|
|
3434
|
+
artifactUrl: `/s/${s.id}/a/${assetToken(s, viewer)}/${encodeURIComponent(path14.basename(s.file))}`,
|
|
3298
3435
|
version: VERSION
|
|
3299
3436
|
};
|
|
3300
3437
|
return `<!doctype html>
|
|
@@ -3328,7 +3465,7 @@ data: ${JSON.stringify({ state: "revoked" })}
|
|
|
3328
3465
|
function hubOpen(res, id) {
|
|
3329
3466
|
const a = /^[a-f0-9]{12}$/.test(id) ? hub.artifact(id) : null;
|
|
3330
3467
|
if (!a) return send(res, 404, "not in the hub");
|
|
3331
|
-
if (!
|
|
3468
|
+
if (!fs15.existsSync(a.file)) return send(res, 410, `${a.file} no longer exists`);
|
|
3332
3469
|
const existed = store.byFile(a.file);
|
|
3333
3470
|
const s = store.ensure(a.file);
|
|
3334
3471
|
if (!existed) store.touch(s);
|
|
@@ -3406,6 +3543,10 @@ data: ${JSON.stringify({ state: "revoked" })}
|
|
|
3406
3543
|
});
|
|
3407
3544
|
return res.end();
|
|
3408
3545
|
}
|
|
3546
|
+
const tokened = /^\/a\/([A-Za-z0-9_-]{43})\/(.*)$/.exec(sub);
|
|
3547
|
+
if (tokened && (req.method === "GET" || req.method === "HEAD") && assetTokenValid(s, tokened[1])) {
|
|
3548
|
+
return serveArtifact(req, res, s, tokened[2]);
|
|
3549
|
+
}
|
|
3409
3550
|
const who = identify(req, s);
|
|
3410
3551
|
if (!who) {
|
|
3411
3552
|
if (tokenFromCookie(req.headers.cookie) == null) return send(res, 403, notOwner(req, "Ask the owner for a link to this page."));
|
|
@@ -3567,8 +3708,8 @@ ${message}`;
|
|
|
3567
3708
|
const html = readFileSafe(s.file);
|
|
3568
3709
|
if (html == null) return send(res, 404, "artifact file is missing");
|
|
3569
3710
|
try {
|
|
3570
|
-
const out = exportHtml(html);
|
|
3571
|
-
const name =
|
|
3711
|
+
const out = exportHtml(html, path14.dirname(s.file));
|
|
3712
|
+
const name = path14.basename(s.file).replace(/\.html?$/i, "") + ".export.html";
|
|
3572
3713
|
return send(res, 200, out.html, {
|
|
3573
3714
|
"content-type": "text/html; charset=utf-8",
|
|
3574
3715
|
"content-disposition": `attachment; filename="${name.replace(/"/g, "")}"`,
|
|
@@ -3585,7 +3726,7 @@ ${message}`;
|
|
|
3585
3726
|
if (listeners.has(host)) return resolve(true);
|
|
3586
3727
|
const server = http3.createServer((req, res) => {
|
|
3587
3728
|
handle(req, res).catch((err) => {
|
|
3588
|
-
log("error", req.method, String(req.url).split("?")[0], String(err?.stack || err));
|
|
3729
|
+
log("error", req.method, String(req.url).split("?")[0].replace(/\/a\/[\w-]{43}\//, "/a/\u2026/"), String(err?.stack || err));
|
|
3589
3730
|
if (!res.headersSent) send(res, err.status || 500, { error: err.status ? String(err.message) : "internal error" });
|
|
3590
3731
|
else res.end();
|
|
3591
3732
|
});
|
|
@@ -3664,6 +3805,7 @@ var MIME, SHORT_GRACE_MS, LOGIN_TTL_MS, OWNER, REVIEWER_KINDS, RENDER_CHECK_AUTH
|
|
|
3664
3805
|
var init_server = __esm({
|
|
3665
3806
|
"src/cli/server.ts"() {
|
|
3666
3807
|
"use strict";
|
|
3808
|
+
init_assets();
|
|
3667
3809
|
init_artifact();
|
|
3668
3810
|
init_export();
|
|
3669
3811
|
init_net();
|
|
@@ -3724,7 +3866,7 @@ __export(mcp_exports, {
|
|
|
3724
3866
|
runMcp: () => runMcp
|
|
3725
3867
|
});
|
|
3726
3868
|
import { spawn as spawn3 } from "node:child_process";
|
|
3727
|
-
import
|
|
3869
|
+
import path15 from "node:path";
|
|
3728
3870
|
import readline from "node:readline";
|
|
3729
3871
|
function runCli({ args, stdin }, signal) {
|
|
3730
3872
|
return new Promise((resolve) => {
|
|
@@ -3767,7 +3909,7 @@ async function callTool(name, a, signal) {
|
|
|
3767
3909
|
const bad = validate2(tool, a);
|
|
3768
3910
|
if (bad) return { content: [{ type: "text", text: `status: error
|
|
3769
3911
|
error: ${bad}` }], isError: true };
|
|
3770
|
-
if (typeof a.file === "string") a = { ...a, file:
|
|
3912
|
+
if (typeof a.file === "string") a = { ...a, file: path15.resolve(a.file) };
|
|
3771
3913
|
const args = a;
|
|
3772
3914
|
let text = "";
|
|
3773
3915
|
let isError = false;
|
|
@@ -3869,7 +4011,7 @@ var init_mcp = __esm({
|
|
|
3869
4011
|
isRecord2 = (v) => !!v && typeof v === "object";
|
|
3870
4012
|
PROTOCOLS = ["2025-11-25", "2025-06-18", "2024-11-05"];
|
|
3871
4013
|
POLL_TIMEOUT_MS = 5e4;
|
|
3872
|
-
INSTRUCTIONS = `austere-axi turns plans, comparisons, decisions, code reviews and reports into review pages the user annotates in the browser. Call \`spec\` once per session for the workflow, the file skeleton and the component reference. Results are the CLI's output: where a \`next:\` hint names an \`austere-axi <command>\`, call the tool of that name instead. Pass absolute file paths. The reviewer judges how a page looks: do not open, screenshot or inspect it yourself unless the user asks.`;
|
|
4014
|
+
INSTRUCTIONS = `austere-axi turns plans, comparisons, decisions, code reviews and reports into review pages the user annotates in the browser. Call \`spec\` once per session for the workflow, the file skeleton and the component reference. Results are the CLI's output: where a \`next:\` hint names an \`austere-axi <command>\`, call the tool of that name instead. Pass absolute file paths. The reviewer judges how a page looks: do not open, screenshot or inspect it yourself unless the user asks. Revise a page only with the \`patch\` tool: send the changed statements (every statement that shows a changed value), never the whole file.`;
|
|
3873
4015
|
file2 = { type: "string", description: "Path of the .html page. Use an absolute path; a relative one resolves against the server's working directory." };
|
|
3874
4016
|
TOOLS = {
|
|
3875
4017
|
spec: {
|
|
@@ -3952,8 +4094,8 @@ var init_mcp = __esm({
|
|
|
3952
4094
|
});
|
|
3953
4095
|
|
|
3954
4096
|
// src/cli/main.ts
|
|
3955
|
-
import
|
|
3956
|
-
import
|
|
4097
|
+
import fs16 from "node:fs";
|
|
4098
|
+
import path16 from "node:path";
|
|
3957
4099
|
|
|
3958
4100
|
// node_modules/@openuidev/lang-core/dist/shared-Dzgc28Wo.mjs
|
|
3959
4101
|
var TELEMETRY_REQUEST_TIMEOUT_MS = 2e3;
|
|
@@ -4814,10 +4956,10 @@ function mergeDefs(...defs) {
|
|
|
4814
4956
|
function cloneDef(schema) {
|
|
4815
4957
|
return mergeDefs(schema._zod.def);
|
|
4816
4958
|
}
|
|
4817
|
-
function getElementAtPath(obj,
|
|
4818
|
-
if (!
|
|
4959
|
+
function getElementAtPath(obj, path17) {
|
|
4960
|
+
if (!path17)
|
|
4819
4961
|
return obj;
|
|
4820
|
-
return
|
|
4962
|
+
return path17.reduce((acc, key2) => acc?.[key2], obj);
|
|
4821
4963
|
}
|
|
4822
4964
|
function promiseAllObject(promisesObj) {
|
|
4823
4965
|
const keys = Object.keys(promisesObj);
|
|
@@ -5157,11 +5299,11 @@ function explicitlyAborted(x, startIndex = 0) {
|
|
|
5157
5299
|
}
|
|
5158
5300
|
return false;
|
|
5159
5301
|
}
|
|
5160
|
-
function prefixIssues(
|
|
5302
|
+
function prefixIssues(path17, issues) {
|
|
5161
5303
|
return issues.map((iss) => {
|
|
5162
5304
|
var _a3;
|
|
5163
5305
|
(_a3 = iss).path ?? (_a3.path = []);
|
|
5164
|
-
iss.path.unshift(
|
|
5306
|
+
iss.path.unshift(path17);
|
|
5165
5307
|
return iss;
|
|
5166
5308
|
});
|
|
5167
5309
|
}
|
|
@@ -5623,16 +5765,16 @@ function flattenError(error62, mapper = (issue2) => issue2.message) {
|
|
|
5623
5765
|
}
|
|
5624
5766
|
function formatError(error62, mapper = (issue2) => issue2.message) {
|
|
5625
5767
|
const fieldErrors = { _errors: [] };
|
|
5626
|
-
const processError = (error63,
|
|
5768
|
+
const processError = (error63, path17 = []) => {
|
|
5627
5769
|
for (const issue2 of error63.issues) {
|
|
5628
5770
|
if (issue2.code === "invalid_union" && issue2.errors.length) {
|
|
5629
|
-
issue2.errors.map((issues) => processError({ issues }, [...
|
|
5771
|
+
issue2.errors.map((issues) => processError({ issues }, [...path17, ...issue2.path]));
|
|
5630
5772
|
} else if (issue2.code === "invalid_key") {
|
|
5631
|
-
processError({ issues: issue2.issues }, [...
|
|
5773
|
+
processError({ issues: issue2.issues }, [...path17, ...issue2.path]);
|
|
5632
5774
|
} else if (issue2.code === "invalid_element") {
|
|
5633
|
-
processError({ issues: issue2.issues }, [...
|
|
5775
|
+
processError({ issues: issue2.issues }, [...path17, ...issue2.path]);
|
|
5634
5776
|
} else {
|
|
5635
|
-
const fullpath = [...
|
|
5777
|
+
const fullpath = [...path17, ...issue2.path];
|
|
5636
5778
|
if (fullpath.length === 0) {
|
|
5637
5779
|
fieldErrors._errors.push(mapper(issue2));
|
|
5638
5780
|
} else {
|
|
@@ -5671,17 +5813,17 @@ function formatError(error62, mapper = (issue2) => issue2.message) {
|
|
|
5671
5813
|
}
|
|
5672
5814
|
function treeifyError(error62, mapper = (issue2) => issue2.message) {
|
|
5673
5815
|
const result = { errors: [] };
|
|
5674
|
-
const processError = (error63,
|
|
5816
|
+
const processError = (error63, path17 = []) => {
|
|
5675
5817
|
var _a3;
|
|
5676
5818
|
for (const issue2 of error63.issues) {
|
|
5677
5819
|
if (issue2.code === "invalid_union" && issue2.errors.length) {
|
|
5678
|
-
issue2.errors.map((issues) => processError({ issues }, [...
|
|
5820
|
+
issue2.errors.map((issues) => processError({ issues }, [...path17, ...issue2.path]));
|
|
5679
5821
|
} else if (issue2.code === "invalid_key") {
|
|
5680
|
-
processError({ issues: issue2.issues }, [...
|
|
5822
|
+
processError({ issues: issue2.issues }, [...path17, ...issue2.path]);
|
|
5681
5823
|
} else if (issue2.code === "invalid_element") {
|
|
5682
|
-
processError({ issues: issue2.issues }, [...
|
|
5824
|
+
processError({ issues: issue2.issues }, [...path17, ...issue2.path]);
|
|
5683
5825
|
} else {
|
|
5684
|
-
const fullpath = [...
|
|
5826
|
+
const fullpath = [...path17, ...issue2.path];
|
|
5685
5827
|
if (fullpath.length === 0) {
|
|
5686
5828
|
result.errors.push(mapper(issue2));
|
|
5687
5829
|
continue;
|
|
@@ -5720,8 +5862,8 @@ function treeifyError(error62, mapper = (issue2) => issue2.message) {
|
|
|
5720
5862
|
}
|
|
5721
5863
|
function toDotPath(_path) {
|
|
5722
5864
|
const segs = [];
|
|
5723
|
-
const
|
|
5724
|
-
for (const seg of
|
|
5865
|
+
const path17 = _path.map((seg) => typeof seg === "object" ? seg.key : seg);
|
|
5866
|
+
for (const seg of path17) {
|
|
5725
5867
|
if (typeof seg === "number")
|
|
5726
5868
|
segs.push(`[${seg}]`);
|
|
5727
5869
|
else if (typeof seg === "symbol")
|
|
@@ -22859,13 +23001,13 @@ function resolveRef(ref, ctx) {
|
|
|
22859
23001
|
if (!ref.startsWith("#")) {
|
|
22860
23002
|
throw new Error("External $ref is not supported, only local refs (#/...) are allowed");
|
|
22861
23003
|
}
|
|
22862
|
-
const
|
|
22863
|
-
if (
|
|
23004
|
+
const path17 = ref.slice(1).split("/").filter(Boolean);
|
|
23005
|
+
if (path17.length === 0) {
|
|
22864
23006
|
return ctx.rootSchema;
|
|
22865
23007
|
}
|
|
22866
23008
|
const defsKey = ctx.version === "draft-2020-12" ? "$defs" : "definitions";
|
|
22867
|
-
if (
|
|
22868
|
-
const key2 =
|
|
23009
|
+
if (path17[0] === defsKey) {
|
|
23010
|
+
const key2 = path17[1] === void 0 ? void 0 : decodeJSONPointerSegment(path17[1]);
|
|
22869
23011
|
if (!key2 || !ctx.defs[key2]) {
|
|
22870
23012
|
throw new Error(`Reference not found: ${ref}`);
|
|
22871
23013
|
}
|
|
@@ -23747,11 +23889,11 @@ function defineAction(config2) {
|
|
|
23747
23889
|
ref: actionRef(config2.name, data)
|
|
23748
23890
|
};
|
|
23749
23891
|
}
|
|
23750
|
-
function resolveField(obj,
|
|
23751
|
-
if (!
|
|
23752
|
-
if (!
|
|
23892
|
+
function resolveField(obj, path17) {
|
|
23893
|
+
if (!path17 || obj == null) return void 0;
|
|
23894
|
+
if (!path17.includes(".")) return obj[path17];
|
|
23753
23895
|
let cur = obj;
|
|
23754
|
-
for (const p of
|
|
23896
|
+
for (const p of path17.split(".")) {
|
|
23755
23897
|
if (cur == null) return void 0;
|
|
23756
23898
|
cur = cur[p];
|
|
23757
23899
|
}
|
|
@@ -25127,14 +25269,14 @@ function checkTypeMismatch(value, info) {
|
|
|
25127
25269
|
};
|
|
25128
25270
|
return null;
|
|
25129
25271
|
}
|
|
25130
|
-
function validationMessage(component,
|
|
25272
|
+
function validationMessage(component, path17, issue2) {
|
|
25131
25273
|
switch (issue2.code) {
|
|
25132
25274
|
case "type-mismatch":
|
|
25133
|
-
return `field "${
|
|
25275
|
+
return `field "${path17}" expects ${issue2.expected} but got ${issue2.actual}`;
|
|
25134
25276
|
case "missing-required":
|
|
25135
|
-
return `missing required field "${
|
|
25277
|
+
return `missing required field "${path17}"${issue2.signature ? ` \u2014 signature: ${issue2.signature}` : ""}`;
|
|
25136
25278
|
case "null-required":
|
|
25137
|
-
return `required field "${
|
|
25279
|
+
return `required field "${path17}" cannot be null${issue2.signature ? ` \u2014 signature: ${issue2.signature}` : ""}`;
|
|
25138
25280
|
case "unknown-component":
|
|
25139
25281
|
return `Unknown component "${component}" \u2014 not found in catalog or builtins${issue2.available?.length ? `. Available components: ${issue2.available.join(", ")}` : ""}`;
|
|
25140
25282
|
case "inline-reserved":
|
|
@@ -25149,12 +25291,12 @@ function validationMessage(component, path16, issue2) {
|
|
|
25149
25291
|
return component ? `No root statement, and no statement calls the root component ${component}` : "No root statement";
|
|
25150
25292
|
}
|
|
25151
25293
|
}
|
|
25152
|
-
function pushValidationIssue(ctx, component,
|
|
25294
|
+
function pushValidationIssue(ctx, component, path17, issue2) {
|
|
25153
25295
|
ctx.errors.push({
|
|
25154
25296
|
code: issue2.code,
|
|
25155
25297
|
component,
|
|
25156
|
-
path:
|
|
25157
|
-
message: validationMessage(component,
|
|
25298
|
+
path: path17,
|
|
25299
|
+
message: validationMessage(component, path17, issue2),
|
|
25158
25300
|
statementId: ctx.currentStatementId,
|
|
25159
25301
|
...issue2.code === "no-root" && issue2.reason === "fallback" && { severity: "warning" }
|
|
25160
25302
|
});
|
|
@@ -25164,10 +25306,10 @@ function resolveInvalidValue(required2, defaultValue) {
|
|
|
25164
25306
|
if (defaultValue !== void 0) return defaultValue;
|
|
25165
25307
|
return required2 ? INVALID2 : void 0;
|
|
25166
25308
|
}
|
|
25167
|
-
function validateElementPosition(element, s, component,
|
|
25309
|
+
function validateElementPosition(element, s, component, path17, ctx) {
|
|
25168
25310
|
if (isCompositeSchema(s)) return false;
|
|
25169
25311
|
if (typeof s["type"] === "string" || Array.isArray(s["enum"]) || "const" in s) {
|
|
25170
|
-
pushValidationIssue(ctx, component,
|
|
25312
|
+
pushValidationIssue(ctx, component, path17, {
|
|
25171
25313
|
code: "type-mismatch",
|
|
25172
25314
|
expected: typeof s["type"] === "string" ? s["type"] : "a literal value",
|
|
25173
25315
|
actual: `component "${element.typeName}"`
|
|
@@ -25183,9 +25325,9 @@ function isOnlyComponentSlot(s, ctx) {
|
|
|
25183
25325
|
const names = slotRefNames(s);
|
|
25184
25326
|
return names.length > 0 && names.every((n) => n !== void 0 && ctx.cat?.has(n));
|
|
25185
25327
|
}
|
|
25186
|
-
function validateObjectValue(value, s, component,
|
|
25328
|
+
function validateObjectValue(value, s, component, path17, ctx) {
|
|
25187
25329
|
if (typeof value !== "object" || Array.isArray(value)) {
|
|
25188
|
-
pushValidationIssue(ctx, component,
|
|
25330
|
+
pushValidationIssue(ctx, component, path17, {
|
|
25189
25331
|
code: "type-mismatch",
|
|
25190
25332
|
expected: "object",
|
|
25191
25333
|
actual: jsType(value)
|
|
@@ -25205,14 +25347,14 @@ function validateObjectValue(value, s, component, path16, ctx) {
|
|
|
25205
25347
|
(out ??= { ...obj })[key2] = fallback;
|
|
25206
25348
|
continue;
|
|
25207
25349
|
}
|
|
25208
|
-
pushValidationIssue(ctx, component, `${
|
|
25350
|
+
pushValidationIssue(ctx, component, `${path17}/${key2}`, { code: present ? "null-required" : "missing-required" });
|
|
25209
25351
|
invalid = true;
|
|
25210
25352
|
}
|
|
25211
25353
|
}
|
|
25212
25354
|
for (const key2 of Object.keys(props)) {
|
|
25213
25355
|
if (!(key2 in obj)) continue;
|
|
25214
25356
|
const sub = props[key2];
|
|
25215
|
-
let next = validateSchemaValue(obj[key2], sub, component, `${
|
|
25357
|
+
let next = validateSchemaValue(obj[key2], sub, component, `${path17}/${key2}`, ctx);
|
|
25216
25358
|
if (next === INVALID2) {
|
|
25217
25359
|
next = resolveInvalidValue(required2.includes(key2), getSchemaDefaultValue(sub));
|
|
25218
25360
|
if (next === INVALID2) {
|
|
@@ -25227,9 +25369,9 @@ function validateObjectValue(value, s, component, path16, ctx) {
|
|
|
25227
25369
|
}
|
|
25228
25370
|
return invalid ? INVALID2 : out ?? obj;
|
|
25229
25371
|
}
|
|
25230
|
-
function validateArrayValue(value, s, component,
|
|
25372
|
+
function validateArrayValue(value, s, component, path17, ctx) {
|
|
25231
25373
|
if (!Array.isArray(value)) {
|
|
25232
|
-
pushValidationIssue(ctx, component,
|
|
25374
|
+
pushValidationIssue(ctx, component, path17, {
|
|
25233
25375
|
code: "type-mismatch",
|
|
25234
25376
|
expected: "array",
|
|
25235
25377
|
actual: jsType(value)
|
|
@@ -25240,19 +25382,19 @@ function validateArrayValue(value, s, component, path16, ctx) {
|
|
|
25240
25382
|
if (!items || typeof items !== "object" || Array.isArray(items)) return value;
|
|
25241
25383
|
let out;
|
|
25242
25384
|
for (let i = 0; i < value.length; i++) {
|
|
25243
|
-
const next = validateSchemaValue(value[i], items, component, `${
|
|
25385
|
+
const next = validateSchemaValue(value[i], items, component, `${path17}/${i}`, ctx);
|
|
25244
25386
|
if (next !== value[i] && !out) out = value.slice(0, i);
|
|
25245
25387
|
if (out && next !== INVALID2) out.push(next);
|
|
25246
25388
|
}
|
|
25247
25389
|
return out ?? value;
|
|
25248
25390
|
}
|
|
25249
|
-
function validateLeafValue(value, s, component,
|
|
25391
|
+
function validateLeafValue(value, s, component, path17, ctx) {
|
|
25250
25392
|
const leaf = getScalarTypeInfo(s);
|
|
25251
25393
|
if (leaf.expectedType == null && leaf.enumValues == null) return false;
|
|
25252
25394
|
if (leaf.enumValues && ctx.partial) return false;
|
|
25253
25395
|
const mismatch = checkTypeMismatch(value, leaf);
|
|
25254
25396
|
if (mismatch) {
|
|
25255
|
-
pushValidationIssue(ctx, component,
|
|
25397
|
+
pushValidationIssue(ctx, component, path17, {
|
|
25256
25398
|
code: "type-mismatch",
|
|
25257
25399
|
...mismatch
|
|
25258
25400
|
});
|
|
@@ -25260,15 +25402,15 @@ function validateLeafValue(value, s, component, path16, ctx) {
|
|
|
25260
25402
|
}
|
|
25261
25403
|
return false;
|
|
25262
25404
|
}
|
|
25263
|
-
function validateSchemaValue(value, schema, component,
|
|
25405
|
+
function validateSchemaValue(value, schema, component, path17, ctx) {
|
|
25264
25406
|
if (!schema || typeof schema !== "object" || Array.isArray(schema)) return value;
|
|
25265
25407
|
const s = schema;
|
|
25266
25408
|
if (value == null) return value;
|
|
25267
25409
|
if (isASTNode(value)) return value;
|
|
25268
|
-
if (isElementNode(value)) return validateElementPosition(value, s, component,
|
|
25410
|
+
if (isElementNode(value)) return validateElementPosition(value, s, component, path17, ctx) ? INVALID2 : value;
|
|
25269
25411
|
if (isCompositeSchema(s)) {
|
|
25270
25412
|
if (!isOnlyComponentSlot(s, ctx)) return value;
|
|
25271
|
-
pushValidationIssue(ctx, component,
|
|
25413
|
+
pushValidationIssue(ctx, component, path17, {
|
|
25272
25414
|
code: "type-mismatch",
|
|
25273
25415
|
expected: slotRefNames(s).join(" | "),
|
|
25274
25416
|
actual: Array.isArray(value) ? "array" : typeof value === "object" ? "plain object" : typeof value
|
|
@@ -25276,9 +25418,9 @@ function validateSchemaValue(value, schema, component, path16, ctx) {
|
|
|
25276
25418
|
return INVALID2;
|
|
25277
25419
|
}
|
|
25278
25420
|
const type = s["type"];
|
|
25279
|
-
if (type === "object") return validateObjectValue(value, s, component,
|
|
25280
|
-
if (type === "array") return validateArrayValue(value, s, component,
|
|
25281
|
-
return validateLeafValue(value, s, component,
|
|
25421
|
+
if (type === "object") return validateObjectValue(value, s, component, path17, ctx);
|
|
25422
|
+
if (type === "array") return validateArrayValue(value, s, component, path17, ctx);
|
|
25423
|
+
return validateLeafValue(value, s, component, path17, ctx) ? INVALID2 : value;
|
|
25282
25424
|
}
|
|
25283
25425
|
function containsDynamicValue(v) {
|
|
25284
25426
|
if (v == null || typeof v !== "object") return false;
|
|
@@ -28904,11 +29046,11 @@ function routeOrthogonal({ boxes, edges: input2, xLines = [], yLines = [], avoid
|
|
|
28904
29046
|
const blocked = solid.some(([id, r]) => id !== e.from && id !== e.to && seg.x0 < r.x + r.width && r.x < seg.x1 && seg.y0 < r.y + r.height && r.y < seg.y1);
|
|
28905
29047
|
if (!blocked) {
|
|
28906
29048
|
routes.set(e.id, [a, b]);
|
|
28907
|
-
const
|
|
29049
|
+
const path18 = [];
|
|
28908
29050
|
const [i0, j0, i1, j1] = [ix(a.x), iy(a.y), ix(b.x), iy(b.y)];
|
|
28909
|
-
if (j0 === j1) for (let i = Math.min(i0, i1); i <= Math.max(i0, i1); i++)
|
|
28910
|
-
else for (let j = Math.min(j0, j1); j <= Math.max(j0, j1); j++)
|
|
28911
|
-
if (
|
|
29051
|
+
if (j0 === j1) for (let i = Math.min(i0, i1); i <= Math.max(i0, i1); i++) path18.push([i, j0]);
|
|
29052
|
+
else for (let j = Math.min(j0, j1); j <= Math.max(j0, j1); j++) path18.push([i0, j]);
|
|
29053
|
+
if (path18.every((pt2) => pt2[0] !== void 0 && pt2[1] !== void 0)) mark(path18);
|
|
28912
29054
|
continue;
|
|
28913
29055
|
}
|
|
28914
29056
|
}
|
|
@@ -28918,12 +29060,12 @@ function routeOrthogonal({ boxes, edges: input2, xLines = [], yLines = [], avoid
|
|
|
28918
29060
|
const sj = iy(st2.y);
|
|
28919
29061
|
const ti = ix(tt2.x);
|
|
28920
29062
|
const tj = iy(tt2.y);
|
|
28921
|
-
let
|
|
29063
|
+
let path17 = null;
|
|
28922
29064
|
if (si !== void 0 && sj !== void 0 && ti !== void 0 && tj !== void 0) {
|
|
28923
|
-
|
|
29065
|
+
path17 = search(si, sj, dirOf(e.fromSide), ti, tj, reverse[dirOf(e.toSide)]);
|
|
28924
29066
|
}
|
|
28925
|
-
const pts =
|
|
28926
|
-
if (
|
|
29067
|
+
const pts = path17 ? path17.map(([i, j]) => ({ x: xs[i], y: ys[j] })) : elbow(st2, tt2, e.fromSide);
|
|
29068
|
+
if (path17) mark(path17);
|
|
28927
29069
|
routes.set(e.id, simplify([e.fromPort, ...pts, e.toPort]));
|
|
28928
29070
|
}
|
|
28929
29071
|
return routes;
|
|
@@ -28992,10 +29134,10 @@ function routeOrthogonal({ boxes, edges: input2, xLines = [], yLines = [], avoid
|
|
|
28992
29134
|
}
|
|
28993
29135
|
return out.reverse();
|
|
28994
29136
|
}
|
|
28995
|
-
function mark(
|
|
28996
|
-
for (let k = 1; k <
|
|
28997
|
-
const [i0, j0] =
|
|
28998
|
-
const [i1, j1] =
|
|
29137
|
+
function mark(path17) {
|
|
29138
|
+
for (let k = 1; k < path17.length; k++) {
|
|
29139
|
+
const [i0, j0] = path17[k - 1];
|
|
29140
|
+
const [i1, j1] = path17[k];
|
|
28999
29141
|
if (j0 === j1) {
|
|
29000
29142
|
hUse[j0 * nx + Math.min(i0, i1)]++;
|
|
29001
29143
|
hPass[j0 * nx + i0]++;
|
|
@@ -29701,53 +29843,52 @@ init_sessions();
|
|
|
29701
29843
|
init_export();
|
|
29702
29844
|
|
|
29703
29845
|
// src/cli/render-check.ts
|
|
29846
|
+
init_artifact();
|
|
29704
29847
|
init_export();
|
|
29705
29848
|
import { spawn as spawn2 } from "node:child_process";
|
|
29706
|
-
import
|
|
29849
|
+
import fs11 from "node:fs";
|
|
29707
29850
|
import http2 from "node:http";
|
|
29708
29851
|
import os2 from "node:os";
|
|
29709
|
-
import
|
|
29852
|
+
import path10 from "node:path";
|
|
29710
29853
|
var WIDTHS = [1280, 390];
|
|
29711
29854
|
var LAUNCH_TIMEOUT_MS = 15e3;
|
|
29712
29855
|
var RENDER_TIMEOUT_MS = 3e4;
|
|
29713
29856
|
var FRAME_SANDBOX = "allow-scripts";
|
|
29714
29857
|
function findChrome() {
|
|
29715
29858
|
const fromEnv = process.env.CHROME_PATH;
|
|
29716
|
-
if (fromEnv) return
|
|
29859
|
+
if (fromEnv) return fs11.existsSync(fromEnv) ? fromEnv : null;
|
|
29717
29860
|
const candidates = [];
|
|
29718
29861
|
if (process.platform === "darwin") {
|
|
29719
29862
|
for (const p of ["Google Chrome.app/Contents/MacOS/Google Chrome", "Chromium.app/Contents/MacOS/Chromium", "Microsoft Edge.app/Contents/MacOS/Microsoft Edge"]) {
|
|
29720
|
-
candidates.push(
|
|
29863
|
+
candidates.push(path10.join("/Applications", p));
|
|
29721
29864
|
}
|
|
29722
29865
|
} else if (process.platform === "win32") {
|
|
29723
29866
|
const roots = [process.env.PROGRAMFILES, process.env["PROGRAMFILES(X86)"], process.env.LOCALAPPDATA].filter((x) => typeof x === "string");
|
|
29724
|
-
for (const r of roots) candidates.push(
|
|
29867
|
+
for (const r of roots) candidates.push(path10.join(r, "Google/Chrome/Application/chrome.exe"), path10.join(r, "Microsoft/Edge/Application/msedge.exe"));
|
|
29725
29868
|
} else {
|
|
29726
|
-
const dirs = (process.env.PATH || "").split(
|
|
29869
|
+
const dirs = (process.env.PATH || "").split(path10.delimiter).filter(Boolean);
|
|
29727
29870
|
for (const name of ["google-chrome", "google-chrome-stable", "chromium", "chromium-browser", "microsoft-edge"]) {
|
|
29728
|
-
for (const d of dirs) candidates.push(
|
|
29871
|
+
for (const d of dirs) candidates.push(path10.join(d, name));
|
|
29729
29872
|
}
|
|
29730
29873
|
}
|
|
29731
|
-
return candidates.find((c) =>
|
|
29874
|
+
return candidates.find((c) => fs11.existsSync(c)) ?? null;
|
|
29732
29875
|
}
|
|
29733
29876
|
var MEASURE = `<script>(() => {
|
|
29734
29877
|
const exceptions = [];
|
|
29735
29878
|
addEventListener("error", (e) => exceptions.push(String((e.error && e.error.message) || e.message || "error")));
|
|
29736
29879
|
addEventListener("unhandledrejection", (e) => exceptions.push(String((e.reason && e.reason.message) || e.reason)));
|
|
29737
29880
|
const sleep = (ms) => new Promise((r) => setTimeout(r, ms));
|
|
29738
|
-
|
|
29739
|
-
|
|
29740
|
-
if (e.source !== parent || !d || d.austereMeasure !== 1) return;
|
|
29881
|
+
const idOf = (el) => (el.closest("[data-oui-id]") && el.closest("[data-oui-id]").getAttribute("data-oui-id")) || "";
|
|
29882
|
+
const settle = async () => {
|
|
29741
29883
|
for (let i = 0; i < 100; i++) {
|
|
29742
29884
|
const pending = [...document.querySelectorAll(".austere-mermaid")].filter((m) => !m.querySelector("svg, .austere-render-error"));
|
|
29743
29885
|
if (!pending.length) break;
|
|
29744
29886
|
await sleep(100);
|
|
29745
29887
|
}
|
|
29746
29888
|
await sleep(200);
|
|
29747
|
-
|
|
29748
|
-
|
|
29749
|
-
|
|
29750
|
-
}));
|
|
29889
|
+
};
|
|
29890
|
+
const snapshot = () => {
|
|
29891
|
+
const shown = [...document.querySelectorAll(".austere-render-error")].map((el) => ({ statement: idOf(el), error: el.textContent.trim().slice(0, 300) }));
|
|
29751
29892
|
const se = document.scrollingElement;
|
|
29752
29893
|
let past = null;
|
|
29753
29894
|
if (se.scrollWidth > se.clientWidth + 1) {
|
|
@@ -29765,11 +29906,58 @@ var MEASURE = `<script>(() => {
|
|
|
29765
29906
|
const out = [...document.body.querySelectorAll("*")].slice(0, 20000).filter(sticksOut);
|
|
29766
29907
|
const outSet = new Set(out);
|
|
29767
29908
|
const leaves = out.filter((el) => ![...el.children].some((c) => outSet.has(c)));
|
|
29768
|
-
|
|
29769
|
-
|
|
29909
|
+
past = leaves.map(idOf).filter(Boolean);
|
|
29910
|
+
}
|
|
29911
|
+
// The sideways check above skips these: the diagram scrolls in its own box, so only a
|
|
29912
|
+
// reader who notices the scroll sees all of it.
|
|
29913
|
+
const wide = [...document.querySelectorAll(".austere-mermaid-svg")]
|
|
29914
|
+
.filter((box) => box.scrollWidth > box.clientWidth + 1)
|
|
29915
|
+
.map((box) => ({ statement: idOf(box), width: box.scrollWidth, box: box.clientWidth }));
|
|
29916
|
+
const ids = [...document.querySelectorAll("[data-oui-id]")].map((el) => el.getAttribute("data-oui-id"));
|
|
29917
|
+
return { shown, past, wide, ids };
|
|
29918
|
+
};
|
|
29919
|
+
// Radix tabs switch on mousedown with the main button.
|
|
29920
|
+
const press = (tab) => tab.dispatchEvent(new MouseEvent("mousedown", { bubbles: true, cancelable: true, button: 0 }));
|
|
29921
|
+
// Opens every tab under \`scope\` (the page, or an open tab panel), measuring each, then walks
|
|
29922
|
+
// the tabs inside each panel while it is open: an inner Tabs mounts only with its panel.
|
|
29923
|
+
// Restores each tab list's open tab. Capped so a huge page cannot stall the check.
|
|
29924
|
+
let presses = 0;
|
|
29925
|
+
const walk = async (scope, snaps) => {
|
|
29926
|
+
const lists = [...scope.querySelectorAll('[role="tablist"]')].filter((l) => (l.parentElement.closest('[role="tabpanel"]') || document) === scope);
|
|
29927
|
+
for (const list of lists) {
|
|
29928
|
+
const count = list.querySelectorAll('[role="tab"]').length;
|
|
29929
|
+
const opened = [...list.querySelectorAll('[role="tab"]')].findIndex((t) => t.getAttribute("aria-selected") === "true");
|
|
29930
|
+
for (let i = 0; i < count && presses < 200; i++) {
|
|
29931
|
+
const tab = list.querySelectorAll('[role="tab"]')[i];
|
|
29932
|
+
if (!tab) break;
|
|
29933
|
+
if (tab.getAttribute("aria-selected") !== "true") {
|
|
29934
|
+
press(tab);
|
|
29935
|
+
presses++;
|
|
29936
|
+
await settle();
|
|
29937
|
+
snaps.push(snapshot());
|
|
29938
|
+
}
|
|
29939
|
+
const panel = document.getElementById(tab.getAttribute("aria-controls") || "");
|
|
29940
|
+
if (panel) await walk(panel, snaps);
|
|
29941
|
+
}
|
|
29942
|
+
const back = list.querySelectorAll('[role="tab"]')[opened];
|
|
29943
|
+
if (back && back.getAttribute("aria-selected") !== "true") press(back);
|
|
29770
29944
|
}
|
|
29771
|
-
|
|
29772
|
-
|
|
29945
|
+
};
|
|
29946
|
+
addEventListener("message", async (e) => {
|
|
29947
|
+
const d = e.data;
|
|
29948
|
+
if (e.source !== parent || !d || d.austereMeasure !== 1) return;
|
|
29949
|
+
await settle();
|
|
29950
|
+
presses = 0;
|
|
29951
|
+
const snaps = [snapshot()];
|
|
29952
|
+
await walk(document, snaps);
|
|
29953
|
+
const overflowed = snaps.filter((x) => x.past);
|
|
29954
|
+
const past = overflowed.length ? [...new Set(overflowed.flatMap((x) => x.past))].slice(0, 8) : null;
|
|
29955
|
+
const shown = [];
|
|
29956
|
+
for (const s of snaps.flatMap((x) => x.shown)) if (!shown.some((y) => y.statement === s.statement && y.error === s.error)) shown.push(s);
|
|
29957
|
+
const wide = [];
|
|
29958
|
+
for (const w of snaps.flatMap((x) => x.wide)) if (!wide.some((y) => y.statement === w.statement)) wide.push(w);
|
|
29959
|
+
const statements = new Set(snaps.flatMap((x) => x.ids)).size;
|
|
29960
|
+
parent.postMessage({ austereMeasured: 1, id: d.id, shown, exceptions: exceptions.slice(0, 20), past, wide, statements }, "*");
|
|
29773
29961
|
});
|
|
29774
29962
|
})();</script>`;
|
|
29775
29963
|
var HARNESS = `<!doctype html><html><head><meta charset="utf-8"></head><body style="margin:0">
|
|
@@ -29800,16 +29988,19 @@ window.__austereReport = async (widths) => {
|
|
|
29800
29988
|
for (let i = 0; i < 150 && !ready; i++) await sleep(100);
|
|
29801
29989
|
const overflow = [];
|
|
29802
29990
|
let last = null;
|
|
29991
|
+
let wide = null;
|
|
29803
29992
|
for (const w of widths) {
|
|
29804
29993
|
f.style.width = w + "px";
|
|
29805
29994
|
await sleep(300);
|
|
29806
29995
|
last = await measure();
|
|
29807
29996
|
if (last.past) overflow.push({ width: w, statements: last.past });
|
|
29997
|
+
// Only the desktop width: on a phone most diagrams scroll, and the page shows that they do.
|
|
29998
|
+
if (!wide) wide = last.wide.map((x) => ({ ...x, at: w }));
|
|
29808
29999
|
}
|
|
29809
30000
|
const all = [...errors];
|
|
29810
30001
|
for (const s of last.shown) if (!all.some((x) => x.statement === s.statement)) all.push(s);
|
|
29811
30002
|
for (const x of last.exceptions) if (!all.some((y) => y.error === x)) all.push({ statement: "", error: x.slice(0, 300) });
|
|
29812
|
-
return { rendered: ready, statements: last.statements, errors: all, overflow };
|
|
30003
|
+
return { rendered: ready, statements: last.statements, errors: all, overflow, wide: wide || [] };
|
|
29813
30004
|
};
|
|
29814
30005
|
</script></body></html>`;
|
|
29815
30006
|
function connect(url2) {
|
|
@@ -29914,14 +30105,23 @@ function withMeasure(html) {
|
|
|
29914
30105
|
const at2 = html.toLowerCase().lastIndexOf("</body>");
|
|
29915
30106
|
return at2 < 0 ? html + MEASURE : html.slice(0, at2) + MEASURE + html.slice(at2);
|
|
29916
30107
|
}
|
|
29917
|
-
|
|
30108
|
+
function wideMessages(html, wide) {
|
|
30109
|
+
const sources = new Map(splitStatements(readArtifact(html).program).map((s) => [s.id, s.text]));
|
|
30110
|
+
return wide.map(({ statement, width, box, at: at2 }) => {
|
|
30111
|
+
const sideways = /\b(?:flowchart|graph)\s+(?:LR|RL)\b/.test(sources.get(statement) ?? "");
|
|
30112
|
+
const fix = sideways ? "use `flowchart TD` or split it" : "split it or shorten its labels";
|
|
30113
|
+
const name = statement || "(not one statement)";
|
|
30114
|
+
return { statement: name, message: `Mermaid ${name} is ${width}px wide at its smallest legible size, more than its ${box}px box at ${at2}px, so it scrolls sideways; ${fix}.` };
|
|
30115
|
+
});
|
|
30116
|
+
}
|
|
30117
|
+
async function renderCheck(html, dir) {
|
|
29918
30118
|
const bin = findChrome();
|
|
29919
30119
|
if (!bin) {
|
|
29920
30120
|
const reason = process.env.CHROME_PATH ? `CHROME_PATH does not exist: ${process.env.CHROME_PATH}` : "no Chrome, Chromium or Edge found; install one or set CHROME_PATH";
|
|
29921
30121
|
return { status: "unavailable", reason };
|
|
29922
30122
|
}
|
|
29923
|
-
const { html: page, notices } = exportHtml(html);
|
|
29924
|
-
const profile =
|
|
30123
|
+
const { html: page, notices } = exportHtml(html, dir);
|
|
30124
|
+
const profile = fs11.mkdtempSync(path10.join(os2.tmpdir(), "austere-render-"));
|
|
29925
30125
|
const site = await serve(withMeasure(page));
|
|
29926
30126
|
const { child, endpoint, exited } = launch(bin, profile);
|
|
29927
30127
|
let cdp = null;
|
|
@@ -29945,7 +30145,7 @@ async function renderCheck(html) {
|
|
|
29945
30145
|
if (r.exceptionDetails) throw new Error(`render report failed: ${r.exceptionDetails.text}`);
|
|
29946
30146
|
const report = r.result.value;
|
|
29947
30147
|
if (!report.rendered && !report.errors.length) report.errors.push({ statement: "", error: "the page did not finish rendering" });
|
|
29948
|
-
return { status: "ok", statements: report.statements, errors: report.errors, overflow: report.overflow, notices };
|
|
30148
|
+
return { status: "ok", statements: report.statements, errors: report.errors, overflow: report.overflow, wide: wideMessages(html, report.wide), notices };
|
|
29949
30149
|
})();
|
|
29950
30150
|
const timeout = new Promise((_, reject) => {
|
|
29951
30151
|
timer = setTimeout(() => reject(new Error(`rendering took longer than ${RENDER_TIMEOUT_MS / 1e3} s`)), RENDER_TIMEOUT_MS);
|
|
@@ -29968,7 +30168,7 @@ async function renderCheck(html) {
|
|
|
29968
30168
|
await Promise.race([exited, new Promise((r) => killGrace = setTimeout(r, 3e3))]);
|
|
29969
30169
|
clearTimeout(killGrace);
|
|
29970
30170
|
try {
|
|
29971
|
-
|
|
30171
|
+
fs11.rmSync(profile, { recursive: true, force: true, maxRetries: 3, retryDelay: 100 });
|
|
29972
30172
|
} catch {
|
|
29973
30173
|
}
|
|
29974
30174
|
}
|
|
@@ -30261,7 +30461,8 @@ NOTES
|
|
|
30261
30461
|
The CDN script tag lets the file open on its own (needs network); review and export work
|
|
30262
30462
|
offline. A browser the CLI did not open gets 403 until it signs in with \`${BIN2} login\`.
|
|
30263
30463
|
Mermaid syntax is only checked when it renders. check warns when an Architecture diagram
|
|
30264
|
-
will not fit the page
|
|
30464
|
+
will not fit the page; check --render, when a Mermaid diagram scrolls sideways in its box.
|
|
30465
|
+
check --render needs Chrome, Chromium or Edge (or CHROME_PATH).
|
|
30265
30466
|
|
|
30266
30467
|
ENV
|
|
30267
30468
|
AUSTERE_AXI_PORT (4388) AUSTERE_AXI_STATE_DIR (~/.austere-axi) AUSTERE_AXI_NO_OPEN=1
|
|
@@ -30427,7 +30628,7 @@ function needFile(file3, cmd) {
|
|
|
30427
30628
|
return null;
|
|
30428
30629
|
}
|
|
30429
30630
|
const abs = canonicalFile(file3);
|
|
30430
|
-
if (!
|
|
30631
|
+
if (!fs16.existsSync(abs)) {
|
|
30431
30632
|
fail(`no such file: ${abs}`);
|
|
30432
30633
|
return null;
|
|
30433
30634
|
}
|
|
@@ -30444,7 +30645,7 @@ function readStdin() {
|
|
|
30444
30645
|
async function replyText(flags) {
|
|
30445
30646
|
if (typeof flags["agent-reply-file"] === "string") {
|
|
30446
30647
|
const f = flags["agent-reply-file"];
|
|
30447
|
-
return (f === "-" ? await readStdin() :
|
|
30648
|
+
return (f === "-" ? await readStdin() : fs16.readFileSync(f, "utf8")).trim();
|
|
30448
30649
|
}
|
|
30449
30650
|
if (typeof flags["agent-reply"] === "string") return flags["agent-reply"].trim();
|
|
30450
30651
|
return "";
|
|
@@ -30483,7 +30684,7 @@ async function cmdHome() {
|
|
|
30483
30684
|
async function cmdOpen(file3, flags) {
|
|
30484
30685
|
const abs = needFile(file3, "open");
|
|
30485
30686
|
if (!abs || file3 === void 0) return;
|
|
30486
|
-
const html =
|
|
30687
|
+
const html = fs16.readFileSync(abs, "utf8");
|
|
30487
30688
|
const check2 = checkHtml(html, { file: quote(file3) });
|
|
30488
30689
|
await ensureServer();
|
|
30489
30690
|
const r = await request("POST", "/api/open", { file: abs, reopen: !!flags.reopen });
|
|
@@ -30522,7 +30723,7 @@ function quote(file3) {
|
|
|
30522
30723
|
function describeItems(abs, items) {
|
|
30523
30724
|
let lines = /* @__PURE__ */ new Map();
|
|
30524
30725
|
try {
|
|
30525
|
-
lines = statementLines(
|
|
30726
|
+
lines = statementLines(fs16.readFileSync(abs, "utf8"));
|
|
30526
30727
|
} catch {
|
|
30527
30728
|
}
|
|
30528
30729
|
const at2 = locator(lines);
|
|
@@ -30539,7 +30740,7 @@ function describeItems(abs, items) {
|
|
|
30539
30740
|
}
|
|
30540
30741
|
function thirdPartyOf(abs) {
|
|
30541
30742
|
try {
|
|
30542
|
-
return pagePacks(
|
|
30743
|
+
return pagePacks(fs16.readFileSync(abs, "utf8")).thirdParty.map((p) => `${p.name}@${p.version}`);
|
|
30543
30744
|
} catch {
|
|
30544
30745
|
return [];
|
|
30545
30746
|
}
|
|
@@ -30565,7 +30766,7 @@ async function cmdPoll(file3, flags) {
|
|
|
30565
30766
|
if (!reply && (flags["agent-reply"] !== void 0 || flags["agent-reply-file"] !== void 0)) {
|
|
30566
30767
|
return fail("the agent reply is empty");
|
|
30567
30768
|
}
|
|
30568
|
-
process.stderr.write(`[${BIN2}] waiting for feedback on ${
|
|
30769
|
+
process.stderr.write(`[${BIN2}] waiting for feedback on ${path16.basename(abs)} (interrupting is safe: feedback stays queued)
|
|
30569
30770
|
`);
|
|
30570
30771
|
const ticker = process.stderr.isTTY ? setInterval(() => process.stderr.write(`[${BIN2}] still waiting\u2026
|
|
30571
30772
|
`), 6e4) : null;
|
|
@@ -30662,13 +30863,13 @@ function fixPacks(abs, html) {
|
|
|
30662
30863
|
return { html, changes };
|
|
30663
30864
|
}
|
|
30664
30865
|
const out = setPacksMeta(html, next);
|
|
30665
|
-
if (out !== html)
|
|
30866
|
+
if (out !== html) fs16.writeFileSync(abs, out);
|
|
30666
30867
|
return { html: out, changes: changes.length ? changes : ["updated integrity hashes"] };
|
|
30667
30868
|
}
|
|
30668
30869
|
async function cmdCheck(file3, flags = {}) {
|
|
30669
30870
|
const abs = needFile(file3, "check");
|
|
30670
30871
|
if (!abs || file3 === void 0) return;
|
|
30671
|
-
let html =
|
|
30872
|
+
let html = fs16.readFileSync(abs, "utf8");
|
|
30672
30873
|
let fixed = [];
|
|
30673
30874
|
if (flags.fix) ({ html, changes: fixed } = fixPacks(abs, html));
|
|
30674
30875
|
const result = checkHtml(html, { file: quote(file3) });
|
|
@@ -30680,7 +30881,7 @@ async function cmdCheck(file3, flags = {}) {
|
|
|
30680
30881
|
if (flags.render) {
|
|
30681
30882
|
if (!result.ok) out.render = "skipped: fix the errors above first";
|
|
30682
30883
|
else {
|
|
30683
|
-
const render = await renderOut(html);
|
|
30884
|
+
const render = await renderOut(html, path16.dirname(abs));
|
|
30684
30885
|
out.render = render;
|
|
30685
30886
|
if (render.errors) out.status = "errors";
|
|
30686
30887
|
else if (render.status === "unavailable") out.status = "render_unavailable";
|
|
@@ -30691,14 +30892,16 @@ async function cmdCheck(file3, flags = {}) {
|
|
|
30691
30892
|
print(out);
|
|
30692
30893
|
if (out.status !== "ok") process.exitCode = 1;
|
|
30693
30894
|
}
|
|
30694
|
-
async function renderOut(html) {
|
|
30695
|
-
const r = await renderCheck(html);
|
|
30895
|
+
async function renderOut(html, dir) {
|
|
30896
|
+
const r = await renderCheck(html, dir);
|
|
30696
30897
|
if (r.status === "unavailable") return { status: "unavailable", reason: r.reason };
|
|
30697
|
-
const
|
|
30898
|
+
const status = r.errors.length ? "errors" : r.overflow.length || r.wide.length ? "warnings" : "clean";
|
|
30899
|
+
const out = { status, widths: "1280, 390", statements: r.statements };
|
|
30698
30900
|
if (r.errors.length) out.errors = r.errors.map((e) => ({ statement: e.statement || "(page)", message: e.error }));
|
|
30699
30901
|
if (r.overflow.length) {
|
|
30700
30902
|
out.scrolls_sideways = r.overflow.map((o) => ({ width: o.width, statements: o.statements.length ? o.statements.join(", ") : "(not one statement)" }));
|
|
30701
30903
|
}
|
|
30904
|
+
if (r.wide.length) out.warnings = r.wide;
|
|
30702
30905
|
if (r.notices.length) out.notices = r.notices;
|
|
30703
30906
|
return out;
|
|
30704
30907
|
}
|
|
@@ -30708,7 +30911,7 @@ async function cmdPatch(file3) {
|
|
|
30708
30911
|
if (process.stdin.isTTY) return usage(`pipe the changed statements on stdin: ${BIN2} patch ${quote(file3)} <<'EOF' ... EOF`, "patch");
|
|
30709
30912
|
const patch = await readStdin();
|
|
30710
30913
|
if (!patch.trim()) return fail("stdin was empty");
|
|
30711
|
-
const html =
|
|
30914
|
+
const html = fs16.readFileSync(abs, "utf8");
|
|
30712
30915
|
const art = readArtifact(html);
|
|
30713
30916
|
if (art.program == null) return fail('no <script type="text/openui"> block to patch');
|
|
30714
30917
|
const merged = mergeStatements(art.program.trim(), patch.trim(), "root");
|
|
@@ -30716,7 +30919,7 @@ async function cmdPatch(file3) {
|
|
|
30716
30919
|
const patched = new Set(splitStatements(patch).filter((s) => !/=\s*null\s*;?$/.test(s.text)).map((s) => s.id));
|
|
30717
30920
|
const dropped = [...patched].filter((id) => !kept.has(id));
|
|
30718
30921
|
const next = replaceProgram(html, merged);
|
|
30719
|
-
|
|
30922
|
+
fs16.writeFileSync(abs, next);
|
|
30720
30923
|
const result = checkHtml(next, { file: quote(file3) });
|
|
30721
30924
|
await registerWithHub(abs, result.title, sessionId(abs));
|
|
30722
30925
|
const out = { status: "patched", file: abs };
|
|
@@ -30731,7 +30934,7 @@ function packSpec(p) {
|
|
|
30731
30934
|
return lines.join("\n") + "\n";
|
|
30732
30935
|
}
|
|
30733
30936
|
function cmdSpec(groups) {
|
|
30734
|
-
let text =
|
|
30937
|
+
let text = fs16.readFileSync(assetPath("prompt.md"), "utf8");
|
|
30735
30938
|
const packs = installedPacks();
|
|
30736
30939
|
const packArgs = groups.filter((g) => packs.some((p) => p.name === g));
|
|
30737
30940
|
if (packArgs.length) {
|
|
@@ -30765,9 +30968,9 @@ ${trimmed.join("\n")}
|
|
|
30765
30968
|
function cmdExport(file3, flags) {
|
|
30766
30969
|
const abs = needFile(file3, "export");
|
|
30767
30970
|
if (!abs) return;
|
|
30768
|
-
const out = typeof flags.out === "string" ?
|
|
30769
|
-
const { html, notices } = exportHtml(
|
|
30770
|
-
|
|
30971
|
+
const out = typeof flags.out === "string" ? path16.resolve(flags.out) : abs.replace(/\.html?$/i, "") + ".export.html";
|
|
30972
|
+
const { html, notices } = exportHtml(fs16.readFileSync(abs, "utf8"), path16.dirname(abs));
|
|
30973
|
+
fs16.writeFileSync(out, html);
|
|
30771
30974
|
print({ status: "exported", file: out, bytes: html.length, notices: notices.length ? notices : void 0 });
|
|
30772
30975
|
}
|
|
30773
30976
|
function printResult(out) {
|
|
@@ -30827,7 +31030,7 @@ async function cmdComponents(sub, args, flags) {
|
|
|
30827
31030
|
pack: r.name,
|
|
30828
31031
|
dir: r.dir,
|
|
30829
31032
|
files: r.files,
|
|
30830
|
-
next: `cd ${quote(
|
|
31033
|
+
next: `cd ${quote(path16.relative(process.cwd(), r.dir) || ".")} && npm install && npm run build, then \`${BIN2} components add .\``
|
|
30831
31034
|
});
|
|
30832
31035
|
} catch (err) {
|
|
30833
31036
|
return fail(messageOf(err));
|
|
@@ -30938,7 +31141,7 @@ async function cmdHub(sub, args, flags) {
|
|
|
30938
31141
|
server: h ? `running on ${port()}${h.persist ? " (persist)" : ""}` : "not running"
|
|
30939
31142
|
};
|
|
30940
31143
|
if (hubEnabled() && h) out.url = url2;
|
|
30941
|
-
if (
|
|
31144
|
+
if (fs16.existsSync(hubDbFile())) {
|
|
30942
31145
|
try {
|
|
30943
31146
|
const hub = await Hub.open();
|
|
30944
31147
|
try {
|
|
@@ -30954,8 +31157,8 @@ async function cmdHub(sub, args, flags) {
|
|
|
30954
31157
|
return print(out);
|
|
30955
31158
|
}
|
|
30956
31159
|
case "list": {
|
|
30957
|
-
if (!
|
|
30958
|
-
const project = typeof flags.project === "string" ?
|
|
31160
|
+
if (!fs16.existsSync(hubDbFile())) return print({ artifacts: "none", next: `\`${BIN2} hub on\` starts indexing.` });
|
|
31161
|
+
const project = typeof flags.project === "string" ? path16.resolve(flags.project) : "";
|
|
30959
31162
|
let hub;
|
|
30960
31163
|
try {
|
|
30961
31164
|
hub = await Hub.open();
|
|
@@ -30980,8 +31183,8 @@ async function cmdHub(sub, args, flags) {
|
|
|
30980
31183
|
});
|
|
30981
31184
|
}
|
|
30982
31185
|
case "notes": {
|
|
30983
|
-
if (!
|
|
30984
|
-
const project = typeof flags.project === "string" ?
|
|
31186
|
+
if (!fs16.existsSync(hubDbFile())) return print({ notes: "none", next: `\`${BIN2} hub on\` starts indexing.` });
|
|
31187
|
+
const project = typeof flags.project === "string" ? path16.resolve(flags.project) : "";
|
|
30985
31188
|
let hub;
|
|
30986
31189
|
try {
|
|
30987
31190
|
hub = await Hub.open();
|
|
@@ -31001,7 +31204,7 @@ async function cmdHub(sub, args, flags) {
|
|
|
31001
31204
|
text: r.text || void 0,
|
|
31002
31205
|
target: r.target || void 0,
|
|
31003
31206
|
status: r.status === "addressed" ? "answered" : r.status === "held" ? "held" : "unanswered",
|
|
31004
|
-
page: r.title ||
|
|
31207
|
+
page: r.title || path16.basename(r.file),
|
|
31005
31208
|
file: r.file,
|
|
31006
31209
|
sent: shortDate(r.at)
|
|
31007
31210
|
})),
|
|
@@ -31125,7 +31328,7 @@ async function main() {
|
|
|
31125
31328
|
let name = null;
|
|
31126
31329
|
if (cmd !== void 0) {
|
|
31127
31330
|
if (Object.hasOwn(COMMANDS, cmd)) name = cmd;
|
|
31128
|
-
else if (/\.html?$/i.test(cmd) ||
|
|
31331
|
+
else if (/\.html?$/i.test(cmd) || fs16.existsSync(cmd)) name = "open";
|
|
31129
31332
|
else if (flags.help) return process.stdout.write(HELP);
|
|
31130
31333
|
else return usage(`unknown command: ${cmd}. One of: ${Object.keys(COMMANDS).join(" ")}, or a page file`);
|
|
31131
31334
|
}
|