@hir4ta/mneme 0.23.2 → 0.24.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/.claude-plugin/plugin.json +1 -1
- package/README.ja.md +27 -6
- package/README.md +27 -6
- package/dist/lib/search/prompt.js +56 -27
- package/dist/public/assets/index-B1iHg48P.css +1 -0
- package/dist/public/assets/index-BzMjX28q.js +377 -0
- package/dist/public/assets/{react-force-graph-2d-B1uwikBG.js → react-force-graph-2d-BRZ1ditM.js} +1 -1
- package/dist/public/index.html +2 -2
- package/dist/server.js +333 -97
- package/dist/servers/db-server.js +66 -31483
- package/dist/servers/search-server.js +47 -30527
- package/package.json +5 -2
- package/servers/search-server.ts +14 -2
- package/skills/reflect/SKILL.md +267 -0
- package/skills/report/SKILL.md +42 -1
- package/skills/report/report-template.html +11 -0
- package/skills/search/SKILL.md +37 -9
- package/dist/public/assets/index-P9gPhKHo.css +0 -1
- package/dist/public/assets/index-huCa1m_y.js +0 -377
package/dist/server.js
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
// dashboard/server/index.ts
|
|
2
|
-
import
|
|
3
|
-
import
|
|
2
|
+
import fs17 from "node:fs";
|
|
3
|
+
import path16 from "node:path";
|
|
4
4
|
|
|
5
5
|
// node_modules/@hono/node-server/dist/index.mjs
|
|
6
6
|
import { createServer as createServerHTTP } from "http";
|
|
@@ -666,10 +666,10 @@ var createStreamBody = (stream) => {
|
|
|
666
666
|
});
|
|
667
667
|
return body;
|
|
668
668
|
};
|
|
669
|
-
var getStats = (
|
|
669
|
+
var getStats = (path17) => {
|
|
670
670
|
let stats;
|
|
671
671
|
try {
|
|
672
|
-
stats = statSync(
|
|
672
|
+
stats = statSync(path17);
|
|
673
673
|
} catch {
|
|
674
674
|
}
|
|
675
675
|
return stats;
|
|
@@ -698,21 +698,21 @@ var serveStatic = (options = { root: "" }) => {
|
|
|
698
698
|
return next();
|
|
699
699
|
}
|
|
700
700
|
}
|
|
701
|
-
let
|
|
701
|
+
let path17 = join(
|
|
702
702
|
root,
|
|
703
703
|
!optionPath && options.rewriteRequestPath ? options.rewriteRequestPath(filename, c) : filename
|
|
704
704
|
);
|
|
705
|
-
let stats = getStats(
|
|
705
|
+
let stats = getStats(path17);
|
|
706
706
|
if (stats && stats.isDirectory()) {
|
|
707
707
|
const indexFile = options.index ?? "index.html";
|
|
708
|
-
|
|
709
|
-
stats = getStats(
|
|
708
|
+
path17 = join(path17, indexFile);
|
|
709
|
+
stats = getStats(path17);
|
|
710
710
|
}
|
|
711
711
|
if (!stats) {
|
|
712
|
-
await options.onNotFound?.(
|
|
712
|
+
await options.onNotFound?.(path17, c);
|
|
713
713
|
return next();
|
|
714
714
|
}
|
|
715
|
-
const mimeType = getMimeType(
|
|
715
|
+
const mimeType = getMimeType(path17);
|
|
716
716
|
c.header("Content-Type", mimeType || "application/octet-stream");
|
|
717
717
|
if (options.precompressed && (!mimeType || COMPRESSIBLE_CONTENT_TYPE_REGEX.test(mimeType))) {
|
|
718
718
|
const acceptEncodingSet = new Set(
|
|
@@ -722,12 +722,12 @@ var serveStatic = (options = { root: "" }) => {
|
|
|
722
722
|
if (!acceptEncodingSet.has(encoding)) {
|
|
723
723
|
continue;
|
|
724
724
|
}
|
|
725
|
-
const precompressedStats = getStats(
|
|
725
|
+
const precompressedStats = getStats(path17 + ENCODINGS[encoding]);
|
|
726
726
|
if (precompressedStats) {
|
|
727
727
|
c.header("Content-Encoding", encoding);
|
|
728
728
|
c.header("Vary", "Accept-Encoding", { append: true });
|
|
729
729
|
stats = precompressedStats;
|
|
730
|
-
|
|
730
|
+
path17 = path17 + ENCODINGS[encoding];
|
|
731
731
|
break;
|
|
732
732
|
}
|
|
733
733
|
}
|
|
@@ -741,7 +741,7 @@ var serveStatic = (options = { root: "" }) => {
|
|
|
741
741
|
result = c.body(null);
|
|
742
742
|
} else if (!range) {
|
|
743
743
|
c.header("Content-Length", size.toString());
|
|
744
|
-
result = c.body(createStreamBody(createReadStream(
|
|
744
|
+
result = c.body(createStreamBody(createReadStream(path17)), 200);
|
|
745
745
|
} else {
|
|
746
746
|
c.header("Accept-Ranges", "bytes");
|
|
747
747
|
c.header("Date", stats.birthtime.toUTCString());
|
|
@@ -752,12 +752,12 @@ var serveStatic = (options = { root: "" }) => {
|
|
|
752
752
|
end = size - 1;
|
|
753
753
|
}
|
|
754
754
|
const chunksize = end - start + 1;
|
|
755
|
-
const stream = createReadStream(
|
|
755
|
+
const stream = createReadStream(path17, { start, end });
|
|
756
756
|
c.header("Content-Length", chunksize.toString());
|
|
757
757
|
c.header("Content-Range", `bytes ${start}-${end}/${stats.size}`);
|
|
758
758
|
result = c.body(createStreamBody(stream), 206);
|
|
759
759
|
}
|
|
760
|
-
await options.onFound?.(
|
|
760
|
+
await options.onFound?.(path17, c);
|
|
761
761
|
return result;
|
|
762
762
|
};
|
|
763
763
|
};
|
|
@@ -879,26 +879,26 @@ var handleParsingNestedValues = (form, key, value) => {
|
|
|
879
879
|
};
|
|
880
880
|
|
|
881
881
|
// node_modules/hono/dist/utils/url.js
|
|
882
|
-
var splitPath = (
|
|
883
|
-
const paths =
|
|
882
|
+
var splitPath = (path17) => {
|
|
883
|
+
const paths = path17.split("/");
|
|
884
884
|
if (paths[0] === "") {
|
|
885
885
|
paths.shift();
|
|
886
886
|
}
|
|
887
887
|
return paths;
|
|
888
888
|
};
|
|
889
889
|
var splitRoutingPath = (routePath) => {
|
|
890
|
-
const { groups, path:
|
|
891
|
-
const paths = splitPath(
|
|
890
|
+
const { groups, path: path17 } = extractGroupsFromPath(routePath);
|
|
891
|
+
const paths = splitPath(path17);
|
|
892
892
|
return replaceGroupMarks(paths, groups);
|
|
893
893
|
};
|
|
894
|
-
var extractGroupsFromPath = (
|
|
894
|
+
var extractGroupsFromPath = (path17) => {
|
|
895
895
|
const groups = [];
|
|
896
|
-
|
|
896
|
+
path17 = path17.replace(/\{[^}]+\}/g, (match2, index) => {
|
|
897
897
|
const mark = `@${index}`;
|
|
898
898
|
groups.push([mark, match2]);
|
|
899
899
|
return mark;
|
|
900
900
|
});
|
|
901
|
-
return { groups, path:
|
|
901
|
+
return { groups, path: path17 };
|
|
902
902
|
};
|
|
903
903
|
var replaceGroupMarks = (paths, groups) => {
|
|
904
904
|
for (let i = groups.length - 1; i >= 0; i--) {
|
|
@@ -955,8 +955,8 @@ var getPath = (request) => {
|
|
|
955
955
|
const queryIndex = url.indexOf("?", i);
|
|
956
956
|
const hashIndex = url.indexOf("#", i);
|
|
957
957
|
const end = queryIndex === -1 ? hashIndex === -1 ? void 0 : hashIndex : hashIndex === -1 ? queryIndex : Math.min(queryIndex, hashIndex);
|
|
958
|
-
const
|
|
959
|
-
return tryDecodeURI(
|
|
958
|
+
const path17 = url.slice(start, end);
|
|
959
|
+
return tryDecodeURI(path17.includes("%25") ? path17.replace(/%25/g, "%2525") : path17);
|
|
960
960
|
} else if (charCode === 63 || charCode === 35) {
|
|
961
961
|
break;
|
|
962
962
|
}
|
|
@@ -973,11 +973,11 @@ var mergePath = (base, sub, ...rest) => {
|
|
|
973
973
|
}
|
|
974
974
|
return `${base?.[0] === "/" ? "" : "/"}${base}${sub === "/" ? "" : `${base?.at(-1) === "/" ? "" : "/"}${sub?.[0] === "/" ? sub.slice(1) : sub}`}`;
|
|
975
975
|
};
|
|
976
|
-
var checkOptionalParameter = (
|
|
977
|
-
if (
|
|
976
|
+
var checkOptionalParameter = (path17) => {
|
|
977
|
+
if (path17.charCodeAt(path17.length - 1) !== 63 || !path17.includes(":")) {
|
|
978
978
|
return null;
|
|
979
979
|
}
|
|
980
|
-
const segments =
|
|
980
|
+
const segments = path17.split("/");
|
|
981
981
|
const results = [];
|
|
982
982
|
let basePath = "";
|
|
983
983
|
segments.forEach((segment) => {
|
|
@@ -1118,9 +1118,9 @@ var HonoRequest = class {
|
|
|
1118
1118
|
*/
|
|
1119
1119
|
path;
|
|
1120
1120
|
bodyCache = {};
|
|
1121
|
-
constructor(request,
|
|
1121
|
+
constructor(request, path17 = "/", matchResult = [[]]) {
|
|
1122
1122
|
this.raw = request;
|
|
1123
|
-
this.path =
|
|
1123
|
+
this.path = path17;
|
|
1124
1124
|
this.#matchResult = matchResult;
|
|
1125
1125
|
this.#validatedData = {};
|
|
1126
1126
|
}
|
|
@@ -1856,8 +1856,8 @@ var Hono = class _Hono {
|
|
|
1856
1856
|
return this;
|
|
1857
1857
|
};
|
|
1858
1858
|
});
|
|
1859
|
-
this.on = (method,
|
|
1860
|
-
for (const p of [
|
|
1859
|
+
this.on = (method, path17, ...handlers) => {
|
|
1860
|
+
for (const p of [path17].flat()) {
|
|
1861
1861
|
this.#path = p;
|
|
1862
1862
|
for (const m of [method].flat()) {
|
|
1863
1863
|
handlers.map((handler) => {
|
|
@@ -1914,8 +1914,8 @@ var Hono = class _Hono {
|
|
|
1914
1914
|
* app.route("/api", app2) // GET /api/user
|
|
1915
1915
|
* ```
|
|
1916
1916
|
*/
|
|
1917
|
-
route(
|
|
1918
|
-
const subApp = this.basePath(
|
|
1917
|
+
route(path17, app2) {
|
|
1918
|
+
const subApp = this.basePath(path17);
|
|
1919
1919
|
app2.routes.map((r) => {
|
|
1920
1920
|
let handler;
|
|
1921
1921
|
if (app2.errorHandler === errorHandler) {
|
|
@@ -1941,9 +1941,9 @@ var Hono = class _Hono {
|
|
|
1941
1941
|
* const api = new Hono().basePath('/api')
|
|
1942
1942
|
* ```
|
|
1943
1943
|
*/
|
|
1944
|
-
basePath(
|
|
1944
|
+
basePath(path17) {
|
|
1945
1945
|
const subApp = this.#clone();
|
|
1946
|
-
subApp._basePath = mergePath(this._basePath,
|
|
1946
|
+
subApp._basePath = mergePath(this._basePath, path17);
|
|
1947
1947
|
return subApp;
|
|
1948
1948
|
}
|
|
1949
1949
|
/**
|
|
@@ -2017,7 +2017,7 @@ var Hono = class _Hono {
|
|
|
2017
2017
|
* })
|
|
2018
2018
|
* ```
|
|
2019
2019
|
*/
|
|
2020
|
-
mount(
|
|
2020
|
+
mount(path17, applicationHandler, options) {
|
|
2021
2021
|
let replaceRequest;
|
|
2022
2022
|
let optionHandler;
|
|
2023
2023
|
if (options) {
|
|
@@ -2044,7 +2044,7 @@ var Hono = class _Hono {
|
|
|
2044
2044
|
return [c.env, executionContext];
|
|
2045
2045
|
};
|
|
2046
2046
|
replaceRequest ||= (() => {
|
|
2047
|
-
const mergedPath = mergePath(this._basePath,
|
|
2047
|
+
const mergedPath = mergePath(this._basePath, path17);
|
|
2048
2048
|
const pathPrefixLength = mergedPath === "/" ? 0 : mergedPath.length;
|
|
2049
2049
|
return (request) => {
|
|
2050
2050
|
const url = new URL(request.url);
|
|
@@ -2059,14 +2059,14 @@ var Hono = class _Hono {
|
|
|
2059
2059
|
}
|
|
2060
2060
|
await next();
|
|
2061
2061
|
};
|
|
2062
|
-
this.#addRoute(METHOD_NAME_ALL, mergePath(
|
|
2062
|
+
this.#addRoute(METHOD_NAME_ALL, mergePath(path17, "*"), handler);
|
|
2063
2063
|
return this;
|
|
2064
2064
|
}
|
|
2065
|
-
#addRoute(method,
|
|
2065
|
+
#addRoute(method, path17, handler) {
|
|
2066
2066
|
method = method.toUpperCase();
|
|
2067
|
-
|
|
2068
|
-
const r = { basePath: this._basePath, path:
|
|
2069
|
-
this.router.add(method,
|
|
2067
|
+
path17 = mergePath(this._basePath, path17);
|
|
2068
|
+
const r = { basePath: this._basePath, path: path17, method, handler };
|
|
2069
|
+
this.router.add(method, path17, [handler, r]);
|
|
2070
2070
|
this.routes.push(r);
|
|
2071
2071
|
}
|
|
2072
2072
|
#handleError(err, c) {
|
|
@@ -2079,10 +2079,10 @@ var Hono = class _Hono {
|
|
|
2079
2079
|
if (method === "HEAD") {
|
|
2080
2080
|
return (async () => new Response(null, await this.#dispatch(request, executionCtx, env, "GET")))();
|
|
2081
2081
|
}
|
|
2082
|
-
const
|
|
2083
|
-
const matchResult = this.router.match(method,
|
|
2082
|
+
const path17 = this.getPath(request, { env });
|
|
2083
|
+
const matchResult = this.router.match(method, path17);
|
|
2084
2084
|
const c = new Context(request, {
|
|
2085
|
-
path:
|
|
2085
|
+
path: path17,
|
|
2086
2086
|
matchResult,
|
|
2087
2087
|
env,
|
|
2088
2088
|
executionCtx,
|
|
@@ -2182,7 +2182,7 @@ var Hono = class _Hono {
|
|
|
2182
2182
|
|
|
2183
2183
|
// node_modules/hono/dist/router/reg-exp-router/matcher.js
|
|
2184
2184
|
var emptyParam = [];
|
|
2185
|
-
function match(method,
|
|
2185
|
+
function match(method, path17) {
|
|
2186
2186
|
const matchers = this.buildAllMatchers();
|
|
2187
2187
|
const match2 = ((method2, path22) => {
|
|
2188
2188
|
const matcher = matchers[method2] || matchers[METHOD_NAME_ALL];
|
|
@@ -2198,7 +2198,7 @@ function match(method, path16) {
|
|
|
2198
2198
|
return [matcher[1][index], match3];
|
|
2199
2199
|
});
|
|
2200
2200
|
this.match = match2;
|
|
2201
|
-
return match2(method,
|
|
2201
|
+
return match2(method, path17);
|
|
2202
2202
|
}
|
|
2203
2203
|
|
|
2204
2204
|
// node_modules/hono/dist/router/reg-exp-router/node.js
|
|
@@ -2313,12 +2313,12 @@ var Node = class _Node {
|
|
|
2313
2313
|
var Trie = class {
|
|
2314
2314
|
#context = { varIndex: 0 };
|
|
2315
2315
|
#root = new Node();
|
|
2316
|
-
insert(
|
|
2316
|
+
insert(path17, index, pathErrorCheckOnly) {
|
|
2317
2317
|
const paramAssoc = [];
|
|
2318
2318
|
const groups = [];
|
|
2319
2319
|
for (let i = 0; ; ) {
|
|
2320
2320
|
let replaced = false;
|
|
2321
|
-
|
|
2321
|
+
path17 = path17.replace(/\{[^}]+\}/g, (m) => {
|
|
2322
2322
|
const mark = `@\\${i}`;
|
|
2323
2323
|
groups[i] = [mark, m];
|
|
2324
2324
|
i++;
|
|
@@ -2329,7 +2329,7 @@ var Trie = class {
|
|
|
2329
2329
|
break;
|
|
2330
2330
|
}
|
|
2331
2331
|
}
|
|
2332
|
-
const tokens =
|
|
2332
|
+
const tokens = path17.match(/(?::[^\/]+)|(?:\/\*$)|./g) || [];
|
|
2333
2333
|
for (let i = groups.length - 1; i >= 0; i--) {
|
|
2334
2334
|
const [mark] = groups[i];
|
|
2335
2335
|
for (let j = tokens.length - 1; j >= 0; j--) {
|
|
@@ -2368,9 +2368,9 @@ var Trie = class {
|
|
|
2368
2368
|
// node_modules/hono/dist/router/reg-exp-router/router.js
|
|
2369
2369
|
var nullMatcher = [/^$/, [], /* @__PURE__ */ Object.create(null)];
|
|
2370
2370
|
var wildcardRegExpCache = /* @__PURE__ */ Object.create(null);
|
|
2371
|
-
function buildWildcardRegExp(
|
|
2372
|
-
return wildcardRegExpCache[
|
|
2373
|
-
|
|
2371
|
+
function buildWildcardRegExp(path17) {
|
|
2372
|
+
return wildcardRegExpCache[path17] ??= new RegExp(
|
|
2373
|
+
path17 === "*" ? "" : `^${path17.replace(
|
|
2374
2374
|
/\/\*$|([.\\+*[^\]$()])/g,
|
|
2375
2375
|
(_, metaChar) => metaChar ? `\\${metaChar}` : "(?:|/.*)"
|
|
2376
2376
|
)}$`
|
|
@@ -2392,17 +2392,17 @@ function buildMatcherFromPreprocessedRoutes(routes) {
|
|
|
2392
2392
|
);
|
|
2393
2393
|
const staticMap = /* @__PURE__ */ Object.create(null);
|
|
2394
2394
|
for (let i = 0, j = -1, len = routesWithStaticPathFlag.length; i < len; i++) {
|
|
2395
|
-
const [pathErrorCheckOnly,
|
|
2395
|
+
const [pathErrorCheckOnly, path17, handlers] = routesWithStaticPathFlag[i];
|
|
2396
2396
|
if (pathErrorCheckOnly) {
|
|
2397
|
-
staticMap[
|
|
2397
|
+
staticMap[path17] = [handlers.map(([h]) => [h, /* @__PURE__ */ Object.create(null)]), emptyParam];
|
|
2398
2398
|
} else {
|
|
2399
2399
|
j++;
|
|
2400
2400
|
}
|
|
2401
2401
|
let paramAssoc;
|
|
2402
2402
|
try {
|
|
2403
|
-
paramAssoc = trie.insert(
|
|
2403
|
+
paramAssoc = trie.insert(path17, j, pathErrorCheckOnly);
|
|
2404
2404
|
} catch (e) {
|
|
2405
|
-
throw e === PATH_ERROR ? new UnsupportedPathError(
|
|
2405
|
+
throw e === PATH_ERROR ? new UnsupportedPathError(path17) : e;
|
|
2406
2406
|
}
|
|
2407
2407
|
if (pathErrorCheckOnly) {
|
|
2408
2408
|
continue;
|
|
@@ -2436,12 +2436,12 @@ function buildMatcherFromPreprocessedRoutes(routes) {
|
|
|
2436
2436
|
}
|
|
2437
2437
|
return [regexp, handlerMap, staticMap];
|
|
2438
2438
|
}
|
|
2439
|
-
function findMiddleware(middleware,
|
|
2439
|
+
function findMiddleware(middleware, path17) {
|
|
2440
2440
|
if (!middleware) {
|
|
2441
2441
|
return void 0;
|
|
2442
2442
|
}
|
|
2443
2443
|
for (const k of Object.keys(middleware).sort((a, b) => b.length - a.length)) {
|
|
2444
|
-
if (buildWildcardRegExp(k).test(
|
|
2444
|
+
if (buildWildcardRegExp(k).test(path17)) {
|
|
2445
2445
|
return [...middleware[k]];
|
|
2446
2446
|
}
|
|
2447
2447
|
}
|
|
@@ -2455,7 +2455,7 @@ var RegExpRouter = class {
|
|
|
2455
2455
|
this.#middleware = { [METHOD_NAME_ALL]: /* @__PURE__ */ Object.create(null) };
|
|
2456
2456
|
this.#routes = { [METHOD_NAME_ALL]: /* @__PURE__ */ Object.create(null) };
|
|
2457
2457
|
}
|
|
2458
|
-
add(method,
|
|
2458
|
+
add(method, path17, handler) {
|
|
2459
2459
|
const middleware = this.#middleware;
|
|
2460
2460
|
const routes = this.#routes;
|
|
2461
2461
|
if (!middleware || !routes) {
|
|
@@ -2470,18 +2470,18 @@ var RegExpRouter = class {
|
|
|
2470
2470
|
});
|
|
2471
2471
|
});
|
|
2472
2472
|
}
|
|
2473
|
-
if (
|
|
2474
|
-
|
|
2473
|
+
if (path17 === "/*") {
|
|
2474
|
+
path17 = "*";
|
|
2475
2475
|
}
|
|
2476
|
-
const paramCount = (
|
|
2477
|
-
if (/\*$/.test(
|
|
2478
|
-
const re = buildWildcardRegExp(
|
|
2476
|
+
const paramCount = (path17.match(/\/:/g) || []).length;
|
|
2477
|
+
if (/\*$/.test(path17)) {
|
|
2478
|
+
const re = buildWildcardRegExp(path17);
|
|
2479
2479
|
if (method === METHOD_NAME_ALL) {
|
|
2480
2480
|
Object.keys(middleware).forEach((m) => {
|
|
2481
|
-
middleware[m][
|
|
2481
|
+
middleware[m][path17] ||= findMiddleware(middleware[m], path17) || findMiddleware(middleware[METHOD_NAME_ALL], path17) || [];
|
|
2482
2482
|
});
|
|
2483
2483
|
} else {
|
|
2484
|
-
middleware[method][
|
|
2484
|
+
middleware[method][path17] ||= findMiddleware(middleware[method], path17) || findMiddleware(middleware[METHOD_NAME_ALL], path17) || [];
|
|
2485
2485
|
}
|
|
2486
2486
|
Object.keys(middleware).forEach((m) => {
|
|
2487
2487
|
if (method === METHOD_NAME_ALL || method === m) {
|
|
@@ -2499,7 +2499,7 @@ var RegExpRouter = class {
|
|
|
2499
2499
|
});
|
|
2500
2500
|
return;
|
|
2501
2501
|
}
|
|
2502
|
-
const paths = checkOptionalParameter(
|
|
2502
|
+
const paths = checkOptionalParameter(path17) || [path17];
|
|
2503
2503
|
for (let i = 0, len = paths.length; i < len; i++) {
|
|
2504
2504
|
const path22 = paths[i];
|
|
2505
2505
|
Object.keys(routes).forEach((m) => {
|
|
@@ -2526,13 +2526,13 @@ var RegExpRouter = class {
|
|
|
2526
2526
|
const routes = [];
|
|
2527
2527
|
let hasOwnRoute = method === METHOD_NAME_ALL;
|
|
2528
2528
|
[this.#middleware, this.#routes].forEach((r) => {
|
|
2529
|
-
const ownRoute = r[method] ? Object.keys(r[method]).map((
|
|
2529
|
+
const ownRoute = r[method] ? Object.keys(r[method]).map((path17) => [path17, r[method][path17]]) : [];
|
|
2530
2530
|
if (ownRoute.length !== 0) {
|
|
2531
2531
|
hasOwnRoute ||= true;
|
|
2532
2532
|
routes.push(...ownRoute);
|
|
2533
2533
|
} else if (method !== METHOD_NAME_ALL) {
|
|
2534
2534
|
routes.push(
|
|
2535
|
-
...Object.keys(r[METHOD_NAME_ALL]).map((
|
|
2535
|
+
...Object.keys(r[METHOD_NAME_ALL]).map((path17) => [path17, r[METHOD_NAME_ALL][path17]])
|
|
2536
2536
|
);
|
|
2537
2537
|
}
|
|
2538
2538
|
});
|
|
@@ -2552,13 +2552,13 @@ var SmartRouter = class {
|
|
|
2552
2552
|
constructor(init) {
|
|
2553
2553
|
this.#routers = init.routers;
|
|
2554
2554
|
}
|
|
2555
|
-
add(method,
|
|
2555
|
+
add(method, path17, handler) {
|
|
2556
2556
|
if (!this.#routes) {
|
|
2557
2557
|
throw new Error(MESSAGE_MATCHER_IS_ALREADY_BUILT);
|
|
2558
2558
|
}
|
|
2559
|
-
this.#routes.push([method,
|
|
2559
|
+
this.#routes.push([method, path17, handler]);
|
|
2560
2560
|
}
|
|
2561
|
-
match(method,
|
|
2561
|
+
match(method, path17) {
|
|
2562
2562
|
if (!this.#routes) {
|
|
2563
2563
|
throw new Error("Fatal error");
|
|
2564
2564
|
}
|
|
@@ -2573,7 +2573,7 @@ var SmartRouter = class {
|
|
|
2573
2573
|
for (let i2 = 0, len2 = routes.length; i2 < len2; i2++) {
|
|
2574
2574
|
router.add(...routes[i2]);
|
|
2575
2575
|
}
|
|
2576
|
-
res = router.match(method,
|
|
2576
|
+
res = router.match(method, path17);
|
|
2577
2577
|
} catch (e) {
|
|
2578
2578
|
if (e instanceof UnsupportedPathError) {
|
|
2579
2579
|
continue;
|
|
@@ -2617,10 +2617,10 @@ var Node2 = class _Node2 {
|
|
|
2617
2617
|
}
|
|
2618
2618
|
this.#patterns = [];
|
|
2619
2619
|
}
|
|
2620
|
-
insert(method,
|
|
2620
|
+
insert(method, path17, handler) {
|
|
2621
2621
|
this.#order = ++this.#order;
|
|
2622
2622
|
let curNode = this;
|
|
2623
|
-
const parts = splitRoutingPath(
|
|
2623
|
+
const parts = splitRoutingPath(path17);
|
|
2624
2624
|
const possibleKeys = [];
|
|
2625
2625
|
for (let i = 0, len = parts.length; i < len; i++) {
|
|
2626
2626
|
const p = parts[i];
|
|
@@ -2671,12 +2671,12 @@ var Node2 = class _Node2 {
|
|
|
2671
2671
|
}
|
|
2672
2672
|
return handlerSets;
|
|
2673
2673
|
}
|
|
2674
|
-
search(method,
|
|
2674
|
+
search(method, path17) {
|
|
2675
2675
|
const handlerSets = [];
|
|
2676
2676
|
this.#params = emptyParams;
|
|
2677
2677
|
const curNode = this;
|
|
2678
2678
|
let curNodes = [curNode];
|
|
2679
|
-
const parts = splitPath(
|
|
2679
|
+
const parts = splitPath(path17);
|
|
2680
2680
|
const curNodesQueue = [];
|
|
2681
2681
|
for (let i = 0, len = parts.length; i < len; i++) {
|
|
2682
2682
|
const part = parts[i];
|
|
@@ -2764,18 +2764,18 @@ var TrieRouter = class {
|
|
|
2764
2764
|
constructor() {
|
|
2765
2765
|
this.#node = new Node2();
|
|
2766
2766
|
}
|
|
2767
|
-
add(method,
|
|
2768
|
-
const results = checkOptionalParameter(
|
|
2767
|
+
add(method, path17, handler) {
|
|
2768
|
+
const results = checkOptionalParameter(path17);
|
|
2769
2769
|
if (results) {
|
|
2770
2770
|
for (let i = 0, len = results.length; i < len; i++) {
|
|
2771
2771
|
this.#node.insert(method, results[i], handler);
|
|
2772
2772
|
}
|
|
2773
2773
|
return;
|
|
2774
2774
|
}
|
|
2775
|
-
this.#node.insert(method,
|
|
2775
|
+
this.#node.insert(method, path17, handler);
|
|
2776
2776
|
}
|
|
2777
|
-
match(method,
|
|
2778
|
-
return this.#node.search(method,
|
|
2777
|
+
match(method, path17) {
|
|
2778
|
+
return this.#node.search(method, path17);
|
|
2779
2779
|
}
|
|
2780
2780
|
};
|
|
2781
2781
|
|
|
@@ -3460,7 +3460,8 @@ function collectDevRules() {
|
|
|
3460
3460
|
updatedAt: entry.updatedAt ? String(entry.updatedAt) : void 0,
|
|
3461
3461
|
context: entry.context ? String(entry.context) : void 0,
|
|
3462
3462
|
reasoning: entry.reasoning ? String(entry.reasoning) : void 0,
|
|
3463
|
-
alternatives: alts
|
|
3463
|
+
alternatives: alts,
|
|
3464
|
+
relatedSessions: Array.isArray(entry.relatedSessions) ? entry.relatedSessions.map((s) => String(s)) : void 0
|
|
3464
3465
|
});
|
|
3465
3466
|
}
|
|
3466
3467
|
}
|
|
@@ -3489,7 +3490,8 @@ function collectDevRules() {
|
|
|
3489
3490
|
updatedAt: entry.updatedAt ? String(entry.updatedAt) : void 0,
|
|
3490
3491
|
context: entry.context ? String(entry.context) : void 0,
|
|
3491
3492
|
patternType: entry.type ? String(entry.type) : void 0,
|
|
3492
|
-
pattern: entry.pattern ? String(entry.pattern) : void 0
|
|
3493
|
+
pattern: entry.pattern ? String(entry.pattern) : void 0,
|
|
3494
|
+
sourceId: entry.sourceId ? String(entry.sourceId) : void 0
|
|
3493
3495
|
});
|
|
3494
3496
|
}
|
|
3495
3497
|
}
|
|
@@ -3501,6 +3503,12 @@ function collectDevRules() {
|
|
|
3501
3503
|
for (const entry of doc.items) {
|
|
3502
3504
|
const id = String(entry.id || "");
|
|
3503
3505
|
if (!id) continue;
|
|
3506
|
+
const sourceRef = entry.sourceRef && typeof entry.sourceRef === "object" && !Array.isArray(entry.sourceRef) ? {
|
|
3507
|
+
type: String(
|
|
3508
|
+
entry.sourceRef.type || ""
|
|
3509
|
+
),
|
|
3510
|
+
id: String(entry.sourceRef.id || "")
|
|
3511
|
+
} : void 0;
|
|
3504
3512
|
items.push({
|
|
3505
3513
|
id,
|
|
3506
3514
|
type: "rule",
|
|
@@ -3513,7 +3521,10 @@ function collectDevRules() {
|
|
|
3513
3521
|
createdAt: String(entry.createdAt || doc.createdAt || ""),
|
|
3514
3522
|
updatedAt: entry.updatedAt ? String(entry.updatedAt) : void 0,
|
|
3515
3523
|
rationale: entry.rationale ? String(entry.rationale) : void 0,
|
|
3516
|
-
category: entry.category ? String(entry.category) : void 0
|
|
3524
|
+
category: entry.category ? String(entry.category) : void 0,
|
|
3525
|
+
sourceRef,
|
|
3526
|
+
appliedCount: typeof entry.appliedCount === "number" ? entry.appliedCount : void 0,
|
|
3527
|
+
acceptedCount: typeof entry.acceptedCount === "number" ? entry.acceptedCount : void 0
|
|
3517
3528
|
});
|
|
3518
3529
|
}
|
|
3519
3530
|
}
|
|
@@ -3689,10 +3700,13 @@ analyticsGraph.get("/knowledge-graph", async (c) => {
|
|
|
3689
3700
|
createdAt: item.createdAt,
|
|
3690
3701
|
unitSubtype: item.type || null,
|
|
3691
3702
|
sourceId: item.sourceFile || null,
|
|
3692
|
-
appliedCount: null,
|
|
3693
|
-
acceptedCount: null,
|
|
3703
|
+
appliedCount: item.appliedCount ?? null,
|
|
3704
|
+
acceptedCount: item.acceptedCount ?? null,
|
|
3694
3705
|
branch: null,
|
|
3695
|
-
resumedFrom: null
|
|
3706
|
+
resumedFrom: null,
|
|
3707
|
+
relatedSessions: item.relatedSessions || null,
|
|
3708
|
+
sourceRef: item.sourceRef || null,
|
|
3709
|
+
patternSourceId: item.sourceId || null
|
|
3696
3710
|
}))
|
|
3697
3711
|
];
|
|
3698
3712
|
const tagToNodes = /* @__PURE__ */ new Map();
|
|
@@ -3744,7 +3758,56 @@ analyticsGraph.get("/knowledge-graph", async (c) => {
|
|
|
3744
3758
|
}
|
|
3745
3759
|
}
|
|
3746
3760
|
}
|
|
3747
|
-
const
|
|
3761
|
+
const relationEdges = [];
|
|
3762
|
+
for (const node of nodes) {
|
|
3763
|
+
if (node.entityType === "rule" && node.relatedSessions) {
|
|
3764
|
+
const related = node.relatedSessions;
|
|
3765
|
+
for (const sessionId of related) {
|
|
3766
|
+
const targetId = `session:${sessionId}`;
|
|
3767
|
+
if (nodeIdSet.has(targetId)) {
|
|
3768
|
+
relationEdges.push({
|
|
3769
|
+
source: node.id,
|
|
3770
|
+
target: targetId,
|
|
3771
|
+
weight: 1,
|
|
3772
|
+
sharedTags: [],
|
|
3773
|
+
edgeType: "relatedSession",
|
|
3774
|
+
directed: true
|
|
3775
|
+
});
|
|
3776
|
+
}
|
|
3777
|
+
}
|
|
3778
|
+
}
|
|
3779
|
+
if (node.entityType === "rule" && node.sourceRef) {
|
|
3780
|
+
const ref = node.sourceRef;
|
|
3781
|
+
if (ref.type && ref.id) {
|
|
3782
|
+
const targetId = `rule:${ref.type}:${ref.id}`;
|
|
3783
|
+
if (nodeIdSet.has(targetId)) {
|
|
3784
|
+
relationEdges.push({
|
|
3785
|
+
source: node.id,
|
|
3786
|
+
target: targetId,
|
|
3787
|
+
weight: 1,
|
|
3788
|
+
sharedTags: [],
|
|
3789
|
+
edgeType: "sourceRef",
|
|
3790
|
+
directed: true
|
|
3791
|
+
});
|
|
3792
|
+
}
|
|
3793
|
+
}
|
|
3794
|
+
}
|
|
3795
|
+
if (node.entityType === "rule" && node.patternSourceId) {
|
|
3796
|
+
const sessionId = node.patternSourceId;
|
|
3797
|
+
const targetId = `session:${sessionId}`;
|
|
3798
|
+
if (nodeIdSet.has(targetId)) {
|
|
3799
|
+
relationEdges.push({
|
|
3800
|
+
source: node.id,
|
|
3801
|
+
target: targetId,
|
|
3802
|
+
weight: 1,
|
|
3803
|
+
sharedTags: [],
|
|
3804
|
+
edgeType: "sessionRef",
|
|
3805
|
+
directed: true
|
|
3806
|
+
});
|
|
3807
|
+
}
|
|
3808
|
+
}
|
|
3809
|
+
}
|
|
3810
|
+
const edges = [...tagEdges, ...resumedEdges, ...relationEdges];
|
|
3748
3811
|
return c.json({ nodes, edges });
|
|
3749
3812
|
} catch (error) {
|
|
3750
3813
|
console.error("Failed to build knowledge graph:", error);
|
|
@@ -4427,7 +4490,7 @@ misc.get("/project", (c) => {
|
|
|
4427
4490
|
}
|
|
4428
4491
|
} catch {
|
|
4429
4492
|
}
|
|
4430
|
-
const version = "0.
|
|
4493
|
+
const version = "0.24.0";
|
|
4431
4494
|
return c.json({
|
|
4432
4495
|
name: projectName,
|
|
4433
4496
|
path: projectRoot,
|
|
@@ -5300,6 +5363,178 @@ sessions.get("/:id/markdown", async (c) => {
|
|
|
5300
5363
|
});
|
|
5301
5364
|
var sessions_default = sessions;
|
|
5302
5365
|
|
|
5366
|
+
// dashboard/server/routes/team.ts
|
|
5367
|
+
import fs16 from "node:fs";
|
|
5368
|
+
import path15 from "node:path";
|
|
5369
|
+
var team = new Hono2();
|
|
5370
|
+
function collectTeamData(mnemeDir2) {
|
|
5371
|
+
const sessionsIndex = readAllSessionIndexes(mnemeDir2);
|
|
5372
|
+
const decisionsIndex = readAllDecisionIndexes(mnemeDir2);
|
|
5373
|
+
const memberMap = /* @__PURE__ */ new Map();
|
|
5374
|
+
function ensureMember(name) {
|
|
5375
|
+
if (!memberMap.has(name)) {
|
|
5376
|
+
memberMap.set(name, {
|
|
5377
|
+
sessions: 0,
|
|
5378
|
+
decisions: 0,
|
|
5379
|
+
patterns: 0,
|
|
5380
|
+
rules: 0,
|
|
5381
|
+
lastActive: ""
|
|
5382
|
+
});
|
|
5383
|
+
}
|
|
5384
|
+
return memberMap.get(name);
|
|
5385
|
+
}
|
|
5386
|
+
function updateLastActive(member, date) {
|
|
5387
|
+
if (date && date > member.lastActive) {
|
|
5388
|
+
member.lastActive = date;
|
|
5389
|
+
}
|
|
5390
|
+
}
|
|
5391
|
+
for (const item of sessionsIndex.items) {
|
|
5392
|
+
if (!item.user) continue;
|
|
5393
|
+
const member = ensureMember(item.user);
|
|
5394
|
+
member.sessions++;
|
|
5395
|
+
updateLastActive(member, item.createdAt);
|
|
5396
|
+
}
|
|
5397
|
+
for (const item of decisionsIndex.items) {
|
|
5398
|
+
if (!item.user) continue;
|
|
5399
|
+
const member = ensureMember(item.user);
|
|
5400
|
+
member.decisions++;
|
|
5401
|
+
updateLastActive(member, item.createdAt);
|
|
5402
|
+
}
|
|
5403
|
+
const patDir = patternsDir();
|
|
5404
|
+
let totalPatterns = 0;
|
|
5405
|
+
if (fs16.existsSync(patDir)) {
|
|
5406
|
+
const patternFiles = listJsonFiles(patDir);
|
|
5407
|
+
for (const filePath of patternFiles) {
|
|
5408
|
+
const doc = safeParseJsonFile(filePath);
|
|
5409
|
+
const entries = doc?.items || doc?.patterns || [];
|
|
5410
|
+
totalPatterns += entries.length;
|
|
5411
|
+
}
|
|
5412
|
+
}
|
|
5413
|
+
if (totalPatterns > 0 && memberMap.size > 0) {
|
|
5414
|
+
let primaryMember = memberMap.values().next().value;
|
|
5415
|
+
for (const stats of memberMap.values()) {
|
|
5416
|
+
if (stats.sessions > (primaryMember?.sessions ?? 0)) {
|
|
5417
|
+
primaryMember = stats;
|
|
5418
|
+
}
|
|
5419
|
+
}
|
|
5420
|
+
if (primaryMember) {
|
|
5421
|
+
primaryMember.patterns = totalPatterns;
|
|
5422
|
+
}
|
|
5423
|
+
}
|
|
5424
|
+
return { memberMap, sessionsIndex, decisionsIndex };
|
|
5425
|
+
}
|
|
5426
|
+
team.get("/overview", async (c) => {
|
|
5427
|
+
try {
|
|
5428
|
+
const mnemeDir2 = getMnemeDir();
|
|
5429
|
+
const { memberMap } = collectTeamData(mnemeDir2);
|
|
5430
|
+
const members = Array.from(memberMap.entries()).map(([name, stats]) => ({ name, ...stats })).sort((a, b) => b.sessions - a.sessions);
|
|
5431
|
+
return c.json({ members });
|
|
5432
|
+
} catch (error) {
|
|
5433
|
+
console.error("Failed to get team overview:", error);
|
|
5434
|
+
return c.json({ error: "Failed to get team overview" }, 500);
|
|
5435
|
+
}
|
|
5436
|
+
});
|
|
5437
|
+
team.get("/activity", async (c) => {
|
|
5438
|
+
try {
|
|
5439
|
+
const mnemeDir2 = getMnemeDir();
|
|
5440
|
+
const daysParam = Number.parseInt(c.req.query("days") || "30", 10);
|
|
5441
|
+
const safeDays = Math.min(Math.max(1, daysParam), 365);
|
|
5442
|
+
const { sessionsIndex, decisionsIndex } = collectTeamData(mnemeDir2);
|
|
5443
|
+
const now = /* @__PURE__ */ new Date();
|
|
5444
|
+
const startDate = new Date(
|
|
5445
|
+
now.getTime() - (safeDays - 1) * 24 * 60 * 60 * 1e3
|
|
5446
|
+
);
|
|
5447
|
+
const activityByDate = {};
|
|
5448
|
+
for (let i = 0; i < safeDays; i++) {
|
|
5449
|
+
const d = new Date(startDate.getTime() + i * 24 * 60 * 60 * 1e3);
|
|
5450
|
+
const dateKey = d.toISOString().split("T")[0];
|
|
5451
|
+
activityByDate[dateKey] = {};
|
|
5452
|
+
}
|
|
5453
|
+
for (const session of sessionsIndex.items) {
|
|
5454
|
+
if (!session.user) continue;
|
|
5455
|
+
const dateKey = session.createdAt.split("T")[0];
|
|
5456
|
+
if (activityByDate[dateKey]) {
|
|
5457
|
+
if (!activityByDate[dateKey][session.user]) {
|
|
5458
|
+
activityByDate[dateKey][session.user] = {
|
|
5459
|
+
sessions: 0,
|
|
5460
|
+
decisions: 0
|
|
5461
|
+
};
|
|
5462
|
+
}
|
|
5463
|
+
activityByDate[dateKey][session.user].sessions++;
|
|
5464
|
+
}
|
|
5465
|
+
}
|
|
5466
|
+
for (const decision of decisionsIndex.items) {
|
|
5467
|
+
if (!decision.user) continue;
|
|
5468
|
+
const dateKey = decision.createdAt.split("T")[0];
|
|
5469
|
+
if (activityByDate[dateKey]) {
|
|
5470
|
+
if (!activityByDate[dateKey][decision.user]) {
|
|
5471
|
+
activityByDate[dateKey][decision.user] = {
|
|
5472
|
+
sessions: 0,
|
|
5473
|
+
decisions: 0
|
|
5474
|
+
};
|
|
5475
|
+
}
|
|
5476
|
+
activityByDate[dateKey][decision.user].decisions++;
|
|
5477
|
+
}
|
|
5478
|
+
}
|
|
5479
|
+
const activity = Object.entries(activityByDate).map(([date, members]) => ({ date, members })).sort((a, b) => a.date.localeCompare(b.date));
|
|
5480
|
+
return c.json({ activity, days: safeDays });
|
|
5481
|
+
} catch (error) {
|
|
5482
|
+
console.error("Failed to get team activity:", error);
|
|
5483
|
+
return c.json({ error: "Failed to get team activity" }, 500);
|
|
5484
|
+
}
|
|
5485
|
+
});
|
|
5486
|
+
team.get("/quality", async (c) => {
|
|
5487
|
+
try {
|
|
5488
|
+
const rDir = rulesDir();
|
|
5489
|
+
let totalRules = 0;
|
|
5490
|
+
let approvedRules = 0;
|
|
5491
|
+
const topRules = [];
|
|
5492
|
+
if (fs16.existsSync(rDir)) {
|
|
5493
|
+
for (const ruleFile of ["dev-rules", "review-guidelines"]) {
|
|
5494
|
+
const filePath = path15.join(rDir, `${ruleFile}.json`);
|
|
5495
|
+
const doc = safeParseJsonFile(filePath);
|
|
5496
|
+
if (!doc?.items) continue;
|
|
5497
|
+
for (const item of doc.items) {
|
|
5498
|
+
totalRules++;
|
|
5499
|
+
if (item.status === "approved") approvedRules++;
|
|
5500
|
+
const applied = typeof item.appliedCount === "number" ? item.appliedCount : 0;
|
|
5501
|
+
const accepted = typeof item.acceptedCount === "number" ? item.acceptedCount : 0;
|
|
5502
|
+
if (applied > 0) {
|
|
5503
|
+
topRules.push({
|
|
5504
|
+
id: String(item.id || ""),
|
|
5505
|
+
text: String(item.text || item.title || item.rule || ""),
|
|
5506
|
+
appliedCount: applied,
|
|
5507
|
+
acceptedCount: accepted
|
|
5508
|
+
});
|
|
5509
|
+
}
|
|
5510
|
+
}
|
|
5511
|
+
}
|
|
5512
|
+
}
|
|
5513
|
+
topRules.sort((a, b) => {
|
|
5514
|
+
const rateA = a.appliedCount > 0 ? a.acceptedCount / a.appliedCount : 0;
|
|
5515
|
+
const rateB = b.appliedCount > 0 ? b.acceptedCount / b.appliedCount : 0;
|
|
5516
|
+
return rateB - rateA;
|
|
5517
|
+
});
|
|
5518
|
+
const withApplied = topRules.filter((r) => r.appliedCount > 0);
|
|
5519
|
+
const least = [...withApplied].sort((a, b) => {
|
|
5520
|
+
const rateA = a.acceptedCount / a.appliedCount;
|
|
5521
|
+
const rateB = b.acceptedCount / b.appliedCount;
|
|
5522
|
+
return rateA - rateB;
|
|
5523
|
+
}).slice(0, 5);
|
|
5524
|
+
return c.json({
|
|
5525
|
+
approvalRate: totalRules > 0 ? Math.round(approvedRules / totalRules * 100) : 0,
|
|
5526
|
+
totalRules,
|
|
5527
|
+
approvedRules,
|
|
5528
|
+
topRules: topRules.slice(0, 5),
|
|
5529
|
+
leastEffective: least
|
|
5530
|
+
});
|
|
5531
|
+
} catch (error) {
|
|
5532
|
+
console.error("Failed to get team quality:", error);
|
|
5533
|
+
return c.json({ error: "Failed to get team quality" }, 500);
|
|
5534
|
+
}
|
|
5535
|
+
});
|
|
5536
|
+
var team_default = team;
|
|
5537
|
+
|
|
5303
5538
|
// dashboard/server/index.ts
|
|
5304
5539
|
var app = new Hono2();
|
|
5305
5540
|
app.use(
|
|
@@ -5318,15 +5553,16 @@ app.route("/api/rules", rules_default);
|
|
|
5318
5553
|
app.route("/api/patterns", patterns_default);
|
|
5319
5554
|
app.route("/api/dev-rules", dev_rules_default);
|
|
5320
5555
|
app.route("/api/export", export_default);
|
|
5556
|
+
app.route("/api/team", team_default);
|
|
5321
5557
|
app.route("/api", analytics_default);
|
|
5322
5558
|
app.route("/api", misc_default);
|
|
5323
|
-
var distPath =
|
|
5324
|
-
if (
|
|
5559
|
+
var distPath = path16.join(import.meta.dirname, "public");
|
|
5560
|
+
if (fs17.existsSync(distPath)) {
|
|
5325
5561
|
app.use("/*", serveStatic({ root: distPath }));
|
|
5326
5562
|
app.get("*", async (c) => {
|
|
5327
|
-
const indexPath =
|
|
5328
|
-
if (
|
|
5329
|
-
const content =
|
|
5563
|
+
const indexPath = path16.join(distPath, "index.html");
|
|
5564
|
+
if (fs17.existsSync(indexPath)) {
|
|
5565
|
+
const content = fs17.readFileSync(indexPath, "utf-8");
|
|
5330
5566
|
return c.html(content);
|
|
5331
5567
|
}
|
|
5332
5568
|
return c.notFound();
|
|
@@ -5335,7 +5571,7 @@ if (fs16.existsSync(distPath)) {
|
|
|
5335
5571
|
var requestedPort = parseInt(process.env.PORT || "7777", 10);
|
|
5336
5572
|
var maxPortAttempts = 10;
|
|
5337
5573
|
var mnemeDir = getMnemeDir();
|
|
5338
|
-
if (
|
|
5574
|
+
if (fs17.existsSync(mnemeDir)) {
|
|
5339
5575
|
try {
|
|
5340
5576
|
const sessionsIndex = readRecentSessionIndexes(mnemeDir, 1);
|
|
5341
5577
|
const decisionsIndex = readRecentDecisionIndexes(mnemeDir, 1);
|