chat-logbook 0.11.0 → 0.13.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +3 -5
- package/api/dist/drizzle/0004_add_tags.sql +16 -0
- package/api/dist/drizzle/archive/0008_add_chats_project_idx.sql +1 -0
- package/api/dist/drizzle/archive/meta/_journal.json +7 -0
- package/api/dist/drizzle/meta/_journal.json +7 -0
- package/api/dist/index.js +1208 -837
- package/package.json +1 -1
- package/web/dist/assets/index-BlF09kci.css +2 -0
- package/web/dist/assets/index-CHr9-eHr.js +57 -0
- package/web/dist/index.html +2 -2
- package/web/dist/assets/index-DHnNZHtV.js +0 -57
- package/web/dist/assets/index-DSNHfjXl.css +0 -2
package/api/dist/index.js
CHANGED
|
@@ -5,11 +5,11 @@ var __export = (target, all) => {
|
|
|
5
5
|
};
|
|
6
6
|
|
|
7
7
|
// src/index.ts
|
|
8
|
-
import
|
|
8
|
+
import fs6 from "fs";
|
|
9
9
|
import os from "os";
|
|
10
|
-
import
|
|
10
|
+
import path4 from "path";
|
|
11
11
|
import { exec } from "child_process";
|
|
12
|
-
import { fileURLToPath as
|
|
12
|
+
import { fileURLToPath as fileURLToPath2 } from "url";
|
|
13
13
|
|
|
14
14
|
// ../node_modules/.pnpm/@hono+node-server@1.19.11_hono@4.12.9/node_modules/@hono/node-server/dist/index.mjs
|
|
15
15
|
import { createServer as createServerHTTP } from "http";
|
|
@@ -588,13 +588,13 @@ import updateNotifier from "update-notifier";
|
|
|
588
588
|
// ../node_modules/.pnpm/hono@4.12.9/node_modules/hono/dist/compose.js
|
|
589
589
|
var compose = (middleware, onError, onNotFound) => {
|
|
590
590
|
return (context, next) => {
|
|
591
|
-
let
|
|
591
|
+
let index2 = -1;
|
|
592
592
|
return dispatch(0);
|
|
593
593
|
async function dispatch(i) {
|
|
594
|
-
if (i <=
|
|
594
|
+
if (i <= index2) {
|
|
595
595
|
throw new Error("next() called multiple times");
|
|
596
596
|
}
|
|
597
|
-
|
|
597
|
+
index2 = i;
|
|
598
598
|
let res;
|
|
599
599
|
let isError = false;
|
|
600
600
|
let handler;
|
|
@@ -692,8 +692,8 @@ var handleParsingNestedValues = (form, key, value) => {
|
|
|
692
692
|
}
|
|
693
693
|
let nestedForm = form;
|
|
694
694
|
const keys = key.split(".");
|
|
695
|
-
keys.forEach((key2,
|
|
696
|
-
if (
|
|
695
|
+
keys.forEach((key2, index2) => {
|
|
696
|
+
if (index2 === keys.length - 1) {
|
|
697
697
|
nestedForm[key2] = value;
|
|
698
698
|
} else {
|
|
699
699
|
if (!nestedForm[key2] || typeof nestedForm[key2] !== "object" || Array.isArray(nestedForm[key2]) || nestedForm[key2] instanceof File) {
|
|
@@ -705,26 +705,26 @@ var handleParsingNestedValues = (form, key, value) => {
|
|
|
705
705
|
};
|
|
706
706
|
|
|
707
707
|
// ../node_modules/.pnpm/hono@4.12.9/node_modules/hono/dist/utils/url.js
|
|
708
|
-
var splitPath = (
|
|
709
|
-
const paths =
|
|
708
|
+
var splitPath = (path5) => {
|
|
709
|
+
const paths = path5.split("/");
|
|
710
710
|
if (paths[0] === "") {
|
|
711
711
|
paths.shift();
|
|
712
712
|
}
|
|
713
713
|
return paths;
|
|
714
714
|
};
|
|
715
715
|
var splitRoutingPath = (routePath) => {
|
|
716
|
-
const { groups, path:
|
|
717
|
-
const paths = splitPath(
|
|
716
|
+
const { groups, path: path5 } = extractGroupsFromPath(routePath);
|
|
717
|
+
const paths = splitPath(path5);
|
|
718
718
|
return replaceGroupMarks(paths, groups);
|
|
719
719
|
};
|
|
720
|
-
var extractGroupsFromPath = (
|
|
720
|
+
var extractGroupsFromPath = (path5) => {
|
|
721
721
|
const groups = [];
|
|
722
|
-
|
|
723
|
-
const mark = `@${
|
|
722
|
+
path5 = path5.replace(/\{[^}]+\}/g, (match2, index2) => {
|
|
723
|
+
const mark = `@${index2}`;
|
|
724
724
|
groups.push([mark, match2]);
|
|
725
725
|
return mark;
|
|
726
726
|
});
|
|
727
|
-
return { groups, path:
|
|
727
|
+
return { groups, path: path5 };
|
|
728
728
|
};
|
|
729
729
|
var replaceGroupMarks = (paths, groups) => {
|
|
730
730
|
for (let i = groups.length - 1; i >= 0; i--) {
|
|
@@ -781,8 +781,8 @@ var getPath = (request) => {
|
|
|
781
781
|
const queryIndex = url.indexOf("?", i);
|
|
782
782
|
const hashIndex = url.indexOf("#", i);
|
|
783
783
|
const end = queryIndex === -1 ? hashIndex === -1 ? void 0 : hashIndex : hashIndex === -1 ? queryIndex : Math.min(queryIndex, hashIndex);
|
|
784
|
-
const
|
|
785
|
-
return tryDecodeURI(
|
|
784
|
+
const path5 = url.slice(start, end);
|
|
785
|
+
return tryDecodeURI(path5.includes("%25") ? path5.replace(/%25/g, "%2525") : path5);
|
|
786
786
|
} else if (charCode === 63 || charCode === 35) {
|
|
787
787
|
break;
|
|
788
788
|
}
|
|
@@ -799,11 +799,11 @@ var mergePath = (base, sub, ...rest) => {
|
|
|
799
799
|
}
|
|
800
800
|
return `${base?.[0] === "/" ? "" : "/"}${base}${sub === "/" ? "" : `${base?.at(-1) === "/" ? "" : "/"}${sub?.[0] === "/" ? sub.slice(1) : sub}`}`;
|
|
801
801
|
};
|
|
802
|
-
var checkOptionalParameter = (
|
|
803
|
-
if (
|
|
802
|
+
var checkOptionalParameter = (path5) => {
|
|
803
|
+
if (path5.charCodeAt(path5.length - 1) !== 63 || !path5.includes(":")) {
|
|
804
804
|
return null;
|
|
805
805
|
}
|
|
806
|
-
const segments =
|
|
806
|
+
const segments = path5.split("/");
|
|
807
807
|
const results = [];
|
|
808
808
|
let basePath = "";
|
|
809
809
|
segments.forEach((segment) => {
|
|
@@ -944,9 +944,9 @@ var HonoRequest = class {
|
|
|
944
944
|
*/
|
|
945
945
|
path;
|
|
946
946
|
bodyCache = {};
|
|
947
|
-
constructor(request,
|
|
947
|
+
constructor(request, path5 = "/", matchResult = [[]]) {
|
|
948
948
|
this.raw = request;
|
|
949
|
-
this.path =
|
|
949
|
+
this.path = path5;
|
|
950
950
|
this.#matchResult = matchResult;
|
|
951
951
|
this.#validatedData = {};
|
|
952
952
|
}
|
|
@@ -1683,8 +1683,8 @@ var Hono = class _Hono {
|
|
|
1683
1683
|
return this;
|
|
1684
1684
|
};
|
|
1685
1685
|
});
|
|
1686
|
-
this.on = (method,
|
|
1687
|
-
for (const p of [
|
|
1686
|
+
this.on = (method, path5, ...handlers) => {
|
|
1687
|
+
for (const p of [path5].flat()) {
|
|
1688
1688
|
this.#path = p;
|
|
1689
1689
|
for (const m of [method].flat()) {
|
|
1690
1690
|
handlers.map((handler) => {
|
|
@@ -1741,8 +1741,8 @@ var Hono = class _Hono {
|
|
|
1741
1741
|
* app.route("/api", app2) // GET /api/user
|
|
1742
1742
|
* ```
|
|
1743
1743
|
*/
|
|
1744
|
-
route(
|
|
1745
|
-
const subApp = this.basePath(
|
|
1744
|
+
route(path5, app2) {
|
|
1745
|
+
const subApp = this.basePath(path5);
|
|
1746
1746
|
app2.routes.map((r) => {
|
|
1747
1747
|
let handler;
|
|
1748
1748
|
if (app2.errorHandler === errorHandler) {
|
|
@@ -1768,9 +1768,9 @@ var Hono = class _Hono {
|
|
|
1768
1768
|
* const api = new Hono().basePath('/api')
|
|
1769
1769
|
* ```
|
|
1770
1770
|
*/
|
|
1771
|
-
basePath(
|
|
1771
|
+
basePath(path5) {
|
|
1772
1772
|
const subApp = this.#clone();
|
|
1773
|
-
subApp._basePath = mergePath(this._basePath,
|
|
1773
|
+
subApp._basePath = mergePath(this._basePath, path5);
|
|
1774
1774
|
return subApp;
|
|
1775
1775
|
}
|
|
1776
1776
|
/**
|
|
@@ -1844,7 +1844,7 @@ var Hono = class _Hono {
|
|
|
1844
1844
|
* })
|
|
1845
1845
|
* ```
|
|
1846
1846
|
*/
|
|
1847
|
-
mount(
|
|
1847
|
+
mount(path5, applicationHandler, options) {
|
|
1848
1848
|
let replaceRequest;
|
|
1849
1849
|
let optionHandler;
|
|
1850
1850
|
if (options) {
|
|
@@ -1871,7 +1871,7 @@ var Hono = class _Hono {
|
|
|
1871
1871
|
return [c.env, executionContext];
|
|
1872
1872
|
};
|
|
1873
1873
|
replaceRequest ||= (() => {
|
|
1874
|
-
const mergedPath = mergePath(this._basePath,
|
|
1874
|
+
const mergedPath = mergePath(this._basePath, path5);
|
|
1875
1875
|
const pathPrefixLength = mergedPath === "/" ? 0 : mergedPath.length;
|
|
1876
1876
|
return (request) => {
|
|
1877
1877
|
const url = new URL(request.url);
|
|
@@ -1886,14 +1886,14 @@ var Hono = class _Hono {
|
|
|
1886
1886
|
}
|
|
1887
1887
|
await next();
|
|
1888
1888
|
};
|
|
1889
|
-
this.#addRoute(METHOD_NAME_ALL, mergePath(
|
|
1889
|
+
this.#addRoute(METHOD_NAME_ALL, mergePath(path5, "*"), handler);
|
|
1890
1890
|
return this;
|
|
1891
1891
|
}
|
|
1892
|
-
#addRoute(method,
|
|
1892
|
+
#addRoute(method, path5, handler) {
|
|
1893
1893
|
method = method.toUpperCase();
|
|
1894
|
-
|
|
1895
|
-
const r = { basePath: this._basePath, path:
|
|
1896
|
-
this.router.add(method,
|
|
1894
|
+
path5 = mergePath(this._basePath, path5);
|
|
1895
|
+
const r = { basePath: this._basePath, path: path5, method, handler };
|
|
1896
|
+
this.router.add(method, path5, [handler, r]);
|
|
1897
1897
|
this.routes.push(r);
|
|
1898
1898
|
}
|
|
1899
1899
|
#handleError(err, c) {
|
|
@@ -1906,10 +1906,10 @@ var Hono = class _Hono {
|
|
|
1906
1906
|
if (method === "HEAD") {
|
|
1907
1907
|
return (async () => new Response(null, await this.#dispatch(request, executionCtx, env, "GET")))();
|
|
1908
1908
|
}
|
|
1909
|
-
const
|
|
1910
|
-
const matchResult = this.router.match(method,
|
|
1909
|
+
const path5 = this.getPath(request, { env });
|
|
1910
|
+
const matchResult = this.router.match(method, path5);
|
|
1911
1911
|
const c = new Context(request, {
|
|
1912
|
-
path:
|
|
1912
|
+
path: path5,
|
|
1913
1913
|
matchResult,
|
|
1914
1914
|
env,
|
|
1915
1915
|
executionCtx,
|
|
@@ -2009,7 +2009,7 @@ var Hono = class _Hono {
|
|
|
2009
2009
|
|
|
2010
2010
|
// ../node_modules/.pnpm/hono@4.12.9/node_modules/hono/dist/router/reg-exp-router/matcher.js
|
|
2011
2011
|
var emptyParam = [];
|
|
2012
|
-
function match(method,
|
|
2012
|
+
function match(method, path5) {
|
|
2013
2013
|
const matchers = this.buildAllMatchers();
|
|
2014
2014
|
const match2 = ((method2, path22) => {
|
|
2015
2015
|
const matcher = matchers[method2] || matchers[METHOD_NAME_ALL];
|
|
@@ -2021,11 +2021,11 @@ function match(method, path6) {
|
|
|
2021
2021
|
if (!match3) {
|
|
2022
2022
|
return [[], emptyParam];
|
|
2023
2023
|
}
|
|
2024
|
-
const
|
|
2025
|
-
return [matcher[1][
|
|
2024
|
+
const index2 = match3.indexOf("", 1);
|
|
2025
|
+
return [matcher[1][index2], match3];
|
|
2026
2026
|
});
|
|
2027
2027
|
this.match = match2;
|
|
2028
|
-
return match2(method,
|
|
2028
|
+
return match2(method, path5);
|
|
2029
2029
|
}
|
|
2030
2030
|
|
|
2031
2031
|
// ../node_modules/.pnpm/hono@4.12.9/node_modules/hono/dist/router/reg-exp-router/node.js
|
|
@@ -2057,7 +2057,7 @@ var Node = class _Node {
|
|
|
2057
2057
|
#index;
|
|
2058
2058
|
#varIndex;
|
|
2059
2059
|
#children = /* @__PURE__ */ Object.create(null);
|
|
2060
|
-
insert(tokens,
|
|
2060
|
+
insert(tokens, index2, paramMap, context, pathErrorCheckOnly) {
|
|
2061
2061
|
if (tokens.length === 0) {
|
|
2062
2062
|
if (this.#index !== void 0) {
|
|
2063
2063
|
throw PATH_ERROR;
|
|
@@ -2065,7 +2065,7 @@ var Node = class _Node {
|
|
|
2065
2065
|
if (pathErrorCheckOnly) {
|
|
2066
2066
|
return;
|
|
2067
2067
|
}
|
|
2068
|
-
this.#index =
|
|
2068
|
+
this.#index = index2;
|
|
2069
2069
|
return;
|
|
2070
2070
|
}
|
|
2071
2071
|
const [token, ...restTokens] = tokens;
|
|
@@ -2115,7 +2115,7 @@ var Node = class _Node {
|
|
|
2115
2115
|
node = this.#children[token] = new _Node();
|
|
2116
2116
|
}
|
|
2117
2117
|
}
|
|
2118
|
-
node.insert(restTokens,
|
|
2118
|
+
node.insert(restTokens, index2, paramMap, context, pathErrorCheckOnly);
|
|
2119
2119
|
}
|
|
2120
2120
|
buildRegExpStr() {
|
|
2121
2121
|
const childKeys = Object.keys(this.#children).sort(compareKey);
|
|
@@ -2140,12 +2140,12 @@ var Node = class _Node {
|
|
|
2140
2140
|
var Trie = class {
|
|
2141
2141
|
#context = { varIndex: 0 };
|
|
2142
2142
|
#root = new Node();
|
|
2143
|
-
insert(
|
|
2143
|
+
insert(path5, index2, pathErrorCheckOnly) {
|
|
2144
2144
|
const paramAssoc = [];
|
|
2145
2145
|
const groups = [];
|
|
2146
2146
|
for (let i = 0; ; ) {
|
|
2147
2147
|
let replaced = false;
|
|
2148
|
-
|
|
2148
|
+
path5 = path5.replace(/\{[^}]+\}/g, (m) => {
|
|
2149
2149
|
const mark = `@\\${i}`;
|
|
2150
2150
|
groups[i] = [mark, m];
|
|
2151
2151
|
i++;
|
|
@@ -2156,7 +2156,7 @@ var Trie = class {
|
|
|
2156
2156
|
break;
|
|
2157
2157
|
}
|
|
2158
2158
|
}
|
|
2159
|
-
const tokens =
|
|
2159
|
+
const tokens = path5.match(/(?::[^\/]+)|(?:\/\*$)|./g) || [];
|
|
2160
2160
|
for (let i = groups.length - 1; i >= 0; i--) {
|
|
2161
2161
|
const [mark] = groups[i];
|
|
2162
2162
|
for (let j = tokens.length - 1; j >= 0; j--) {
|
|
@@ -2166,7 +2166,7 @@ var Trie = class {
|
|
|
2166
2166
|
}
|
|
2167
2167
|
}
|
|
2168
2168
|
}
|
|
2169
|
-
this.#root.insert(tokens,
|
|
2169
|
+
this.#root.insert(tokens, index2, paramAssoc, this.#context, pathErrorCheckOnly);
|
|
2170
2170
|
return paramAssoc;
|
|
2171
2171
|
}
|
|
2172
2172
|
buildRegExp() {
|
|
@@ -2195,9 +2195,9 @@ var Trie = class {
|
|
|
2195
2195
|
// ../node_modules/.pnpm/hono@4.12.9/node_modules/hono/dist/router/reg-exp-router/router.js
|
|
2196
2196
|
var nullMatcher = [/^$/, [], /* @__PURE__ */ Object.create(null)];
|
|
2197
2197
|
var wildcardRegExpCache = /* @__PURE__ */ Object.create(null);
|
|
2198
|
-
function buildWildcardRegExp(
|
|
2199
|
-
return wildcardRegExpCache[
|
|
2200
|
-
|
|
2198
|
+
function buildWildcardRegExp(path5) {
|
|
2199
|
+
return wildcardRegExpCache[path5] ??= new RegExp(
|
|
2200
|
+
path5 === "*" ? "" : `^${path5.replace(
|
|
2201
2201
|
/\/\*$|([.\\+*[^\]$()])/g,
|
|
2202
2202
|
(_, metaChar) => metaChar ? `\\${metaChar}` : "(?:|/.*)"
|
|
2203
2203
|
)}$`
|
|
@@ -2219,17 +2219,17 @@ function buildMatcherFromPreprocessedRoutes(routes) {
|
|
|
2219
2219
|
);
|
|
2220
2220
|
const staticMap = /* @__PURE__ */ Object.create(null);
|
|
2221
2221
|
for (let i = 0, j = -1, len = routesWithStaticPathFlag.length; i < len; i++) {
|
|
2222
|
-
const [pathErrorCheckOnly,
|
|
2222
|
+
const [pathErrorCheckOnly, path5, handlers] = routesWithStaticPathFlag[i];
|
|
2223
2223
|
if (pathErrorCheckOnly) {
|
|
2224
|
-
staticMap[
|
|
2224
|
+
staticMap[path5] = [handlers.map(([h]) => [h, /* @__PURE__ */ Object.create(null)]), emptyParam];
|
|
2225
2225
|
} else {
|
|
2226
2226
|
j++;
|
|
2227
2227
|
}
|
|
2228
2228
|
let paramAssoc;
|
|
2229
2229
|
try {
|
|
2230
|
-
paramAssoc = trie.insert(
|
|
2230
|
+
paramAssoc = trie.insert(path5, j, pathErrorCheckOnly);
|
|
2231
2231
|
} catch (e) {
|
|
2232
|
-
throw e === PATH_ERROR ? new UnsupportedPathError(
|
|
2232
|
+
throw e === PATH_ERROR ? new UnsupportedPathError(path5) : e;
|
|
2233
2233
|
}
|
|
2234
2234
|
if (pathErrorCheckOnly) {
|
|
2235
2235
|
continue;
|
|
@@ -2263,12 +2263,12 @@ function buildMatcherFromPreprocessedRoutes(routes) {
|
|
|
2263
2263
|
}
|
|
2264
2264
|
return [regexp, handlerMap, staticMap];
|
|
2265
2265
|
}
|
|
2266
|
-
function findMiddleware(middleware,
|
|
2266
|
+
function findMiddleware(middleware, path5) {
|
|
2267
2267
|
if (!middleware) {
|
|
2268
2268
|
return void 0;
|
|
2269
2269
|
}
|
|
2270
2270
|
for (const k of Object.keys(middleware).sort((a, b) => b.length - a.length)) {
|
|
2271
|
-
if (buildWildcardRegExp(k).test(
|
|
2271
|
+
if (buildWildcardRegExp(k).test(path5)) {
|
|
2272
2272
|
return [...middleware[k]];
|
|
2273
2273
|
}
|
|
2274
2274
|
}
|
|
@@ -2282,7 +2282,7 @@ var RegExpRouter = class {
|
|
|
2282
2282
|
this.#middleware = { [METHOD_NAME_ALL]: /* @__PURE__ */ Object.create(null) };
|
|
2283
2283
|
this.#routes = { [METHOD_NAME_ALL]: /* @__PURE__ */ Object.create(null) };
|
|
2284
2284
|
}
|
|
2285
|
-
add(method,
|
|
2285
|
+
add(method, path5, handler) {
|
|
2286
2286
|
const middleware = this.#middleware;
|
|
2287
2287
|
const routes = this.#routes;
|
|
2288
2288
|
if (!middleware || !routes) {
|
|
@@ -2297,18 +2297,18 @@ var RegExpRouter = class {
|
|
|
2297
2297
|
});
|
|
2298
2298
|
});
|
|
2299
2299
|
}
|
|
2300
|
-
if (
|
|
2301
|
-
|
|
2300
|
+
if (path5 === "/*") {
|
|
2301
|
+
path5 = "*";
|
|
2302
2302
|
}
|
|
2303
|
-
const paramCount = (
|
|
2304
|
-
if (/\*$/.test(
|
|
2305
|
-
const re = buildWildcardRegExp(
|
|
2303
|
+
const paramCount = (path5.match(/\/:/g) || []).length;
|
|
2304
|
+
if (/\*$/.test(path5)) {
|
|
2305
|
+
const re = buildWildcardRegExp(path5);
|
|
2306
2306
|
if (method === METHOD_NAME_ALL) {
|
|
2307
2307
|
Object.keys(middleware).forEach((m) => {
|
|
2308
|
-
middleware[m][
|
|
2308
|
+
middleware[m][path5] ||= findMiddleware(middleware[m], path5) || findMiddleware(middleware[METHOD_NAME_ALL], path5) || [];
|
|
2309
2309
|
});
|
|
2310
2310
|
} else {
|
|
2311
|
-
middleware[method][
|
|
2311
|
+
middleware[method][path5] ||= findMiddleware(middleware[method], path5) || findMiddleware(middleware[METHOD_NAME_ALL], path5) || [];
|
|
2312
2312
|
}
|
|
2313
2313
|
Object.keys(middleware).forEach((m) => {
|
|
2314
2314
|
if (method === METHOD_NAME_ALL || method === m) {
|
|
@@ -2326,7 +2326,7 @@ var RegExpRouter = class {
|
|
|
2326
2326
|
});
|
|
2327
2327
|
return;
|
|
2328
2328
|
}
|
|
2329
|
-
const paths = checkOptionalParameter(
|
|
2329
|
+
const paths = checkOptionalParameter(path5) || [path5];
|
|
2330
2330
|
for (let i = 0, len = paths.length; i < len; i++) {
|
|
2331
2331
|
const path22 = paths[i];
|
|
2332
2332
|
Object.keys(routes).forEach((m) => {
|
|
@@ -2353,13 +2353,13 @@ var RegExpRouter = class {
|
|
|
2353
2353
|
const routes = [];
|
|
2354
2354
|
let hasOwnRoute = method === METHOD_NAME_ALL;
|
|
2355
2355
|
[this.#middleware, this.#routes].forEach((r) => {
|
|
2356
|
-
const ownRoute = r[method] ? Object.keys(r[method]).map((
|
|
2356
|
+
const ownRoute = r[method] ? Object.keys(r[method]).map((path5) => [path5, r[method][path5]]) : [];
|
|
2357
2357
|
if (ownRoute.length !== 0) {
|
|
2358
2358
|
hasOwnRoute ||= true;
|
|
2359
2359
|
routes.push(...ownRoute);
|
|
2360
2360
|
} else if (method !== METHOD_NAME_ALL) {
|
|
2361
2361
|
routes.push(
|
|
2362
|
-
...Object.keys(r[METHOD_NAME_ALL]).map((
|
|
2362
|
+
...Object.keys(r[METHOD_NAME_ALL]).map((path5) => [path5, r[METHOD_NAME_ALL][path5]])
|
|
2363
2363
|
);
|
|
2364
2364
|
}
|
|
2365
2365
|
});
|
|
@@ -2379,13 +2379,13 @@ var SmartRouter = class {
|
|
|
2379
2379
|
constructor(init) {
|
|
2380
2380
|
this.#routers = init.routers;
|
|
2381
2381
|
}
|
|
2382
|
-
add(method,
|
|
2382
|
+
add(method, path5, handler) {
|
|
2383
2383
|
if (!this.#routes) {
|
|
2384
2384
|
throw new Error(MESSAGE_MATCHER_IS_ALREADY_BUILT);
|
|
2385
2385
|
}
|
|
2386
|
-
this.#routes.push([method,
|
|
2386
|
+
this.#routes.push([method, path5, handler]);
|
|
2387
2387
|
}
|
|
2388
|
-
match(method,
|
|
2388
|
+
match(method, path5) {
|
|
2389
2389
|
if (!this.#routes) {
|
|
2390
2390
|
throw new Error("Fatal error");
|
|
2391
2391
|
}
|
|
@@ -2400,7 +2400,7 @@ var SmartRouter = class {
|
|
|
2400
2400
|
for (let i2 = 0, len2 = routes.length; i2 < len2; i2++) {
|
|
2401
2401
|
router.add(...routes[i2]);
|
|
2402
2402
|
}
|
|
2403
|
-
res = router.match(method,
|
|
2403
|
+
res = router.match(method, path5);
|
|
2404
2404
|
} catch (e) {
|
|
2405
2405
|
if (e instanceof UnsupportedPathError) {
|
|
2406
2406
|
continue;
|
|
@@ -2450,10 +2450,10 @@ var Node2 = class _Node2 {
|
|
|
2450
2450
|
}
|
|
2451
2451
|
this.#patterns = [];
|
|
2452
2452
|
}
|
|
2453
|
-
insert(method,
|
|
2453
|
+
insert(method, path5, handler) {
|
|
2454
2454
|
this.#order = ++this.#order;
|
|
2455
2455
|
let curNode = this;
|
|
2456
|
-
const parts = splitRoutingPath(
|
|
2456
|
+
const parts = splitRoutingPath(path5);
|
|
2457
2457
|
const possibleKeys = [];
|
|
2458
2458
|
for (let i = 0, len = parts.length; i < len; i++) {
|
|
2459
2459
|
const p = parts[i];
|
|
@@ -2502,12 +2502,12 @@ var Node2 = class _Node2 {
|
|
|
2502
2502
|
}
|
|
2503
2503
|
}
|
|
2504
2504
|
}
|
|
2505
|
-
search(method,
|
|
2505
|
+
search(method, path5) {
|
|
2506
2506
|
const handlerSets = [];
|
|
2507
2507
|
this.#params = emptyParams;
|
|
2508
2508
|
const curNode = this;
|
|
2509
2509
|
let curNodes = [curNode];
|
|
2510
|
-
const parts = splitPath(
|
|
2510
|
+
const parts = splitPath(path5);
|
|
2511
2511
|
const curNodesQueue = [];
|
|
2512
2512
|
const len = parts.length;
|
|
2513
2513
|
let partOffsets = null;
|
|
@@ -2549,13 +2549,13 @@ var Node2 = class _Node2 {
|
|
|
2549
2549
|
if (matcher instanceof RegExp) {
|
|
2550
2550
|
if (partOffsets === null) {
|
|
2551
2551
|
partOffsets = new Array(len);
|
|
2552
|
-
let offset =
|
|
2552
|
+
let offset = path5[0] === "/" ? 1 : 0;
|
|
2553
2553
|
for (let p = 0; p < len; p++) {
|
|
2554
2554
|
partOffsets[p] = offset;
|
|
2555
2555
|
offset += parts[p].length + 1;
|
|
2556
2556
|
}
|
|
2557
2557
|
}
|
|
2558
|
-
const restPathString =
|
|
2558
|
+
const restPathString = path5.substring(partOffsets[i]);
|
|
2559
2559
|
const m = matcher.exec(restPathString);
|
|
2560
2560
|
if (m) {
|
|
2561
2561
|
params[name] = m[0];
|
|
@@ -2608,18 +2608,18 @@ var TrieRouter = class {
|
|
|
2608
2608
|
constructor() {
|
|
2609
2609
|
this.#node = new Node2();
|
|
2610
2610
|
}
|
|
2611
|
-
add(method,
|
|
2612
|
-
const results = checkOptionalParameter(
|
|
2611
|
+
add(method, path5, handler) {
|
|
2612
|
+
const results = checkOptionalParameter(path5);
|
|
2613
2613
|
if (results) {
|
|
2614
2614
|
for (let i = 0, len = results.length; i < len; i++) {
|
|
2615
2615
|
this.#node.insert(method, results[i], handler);
|
|
2616
2616
|
}
|
|
2617
2617
|
return;
|
|
2618
2618
|
}
|
|
2619
|
-
this.#node.insert(method,
|
|
2619
|
+
this.#node.insert(method, path5, handler);
|
|
2620
2620
|
}
|
|
2621
|
-
match(method,
|
|
2622
|
-
return this.#node.search(method,
|
|
2621
|
+
match(method, path5) {
|
|
2622
|
+
return this.#node.search(method, path5);
|
|
2623
2623
|
}
|
|
2624
2624
|
};
|
|
2625
2625
|
|
|
@@ -2750,10 +2750,10 @@ var createStreamBody = (stream) => {
|
|
|
2750
2750
|
});
|
|
2751
2751
|
return body;
|
|
2752
2752
|
};
|
|
2753
|
-
var getStats = (
|
|
2753
|
+
var getStats = (path5) => {
|
|
2754
2754
|
let stats;
|
|
2755
2755
|
try {
|
|
2756
|
-
stats = statSync(
|
|
2756
|
+
stats = statSync(path5);
|
|
2757
2757
|
} catch {
|
|
2758
2758
|
}
|
|
2759
2759
|
return stats;
|
|
@@ -2796,21 +2796,21 @@ var serveStatic = (options = { root: "" }) => {
|
|
|
2796
2796
|
return next();
|
|
2797
2797
|
}
|
|
2798
2798
|
}
|
|
2799
|
-
let
|
|
2799
|
+
let path5 = join(
|
|
2800
2800
|
root,
|
|
2801
2801
|
!optionPath && options.rewriteRequestPath ? options.rewriteRequestPath(filename, c) : filename
|
|
2802
2802
|
);
|
|
2803
|
-
let stats = getStats(
|
|
2803
|
+
let stats = getStats(path5);
|
|
2804
2804
|
if (stats && stats.isDirectory()) {
|
|
2805
2805
|
const indexFile = options.index ?? "index.html";
|
|
2806
|
-
|
|
2807
|
-
stats = getStats(
|
|
2806
|
+
path5 = join(path5, indexFile);
|
|
2807
|
+
stats = getStats(path5);
|
|
2808
2808
|
}
|
|
2809
2809
|
if (!stats) {
|
|
2810
|
-
await options.onNotFound?.(
|
|
2810
|
+
await options.onNotFound?.(path5, c);
|
|
2811
2811
|
return next();
|
|
2812
2812
|
}
|
|
2813
|
-
const mimeType = getMimeType(
|
|
2813
|
+
const mimeType = getMimeType(path5);
|
|
2814
2814
|
c.header("Content-Type", mimeType || "application/octet-stream");
|
|
2815
2815
|
if (options.precompressed && (!mimeType || COMPRESSIBLE_CONTENT_TYPE_REGEX.test(mimeType))) {
|
|
2816
2816
|
const acceptEncodingSet = new Set(
|
|
@@ -2820,12 +2820,12 @@ var serveStatic = (options = { root: "" }) => {
|
|
|
2820
2820
|
if (!acceptEncodingSet.has(encoding)) {
|
|
2821
2821
|
continue;
|
|
2822
2822
|
}
|
|
2823
|
-
const precompressedStats = getStats(
|
|
2823
|
+
const precompressedStats = getStats(path5 + ENCODINGS[encoding]);
|
|
2824
2824
|
if (precompressedStats) {
|
|
2825
2825
|
c.header("Content-Encoding", encoding);
|
|
2826
2826
|
c.header("Vary", "Accept-Encoding", { append: true });
|
|
2827
2827
|
stats = precompressedStats;
|
|
2828
|
-
|
|
2828
|
+
path5 = path5 + ENCODINGS[encoding];
|
|
2829
2829
|
break;
|
|
2830
2830
|
}
|
|
2831
2831
|
}
|
|
@@ -2839,7 +2839,7 @@ var serveStatic = (options = { root: "" }) => {
|
|
|
2839
2839
|
result = c.body(null);
|
|
2840
2840
|
} else if (!range) {
|
|
2841
2841
|
c.header("Content-Length", size.toString());
|
|
2842
|
-
result = c.body(createStreamBody(createReadStream(
|
|
2842
|
+
result = c.body(createStreamBody(createReadStream(path5)), 200);
|
|
2843
2843
|
} else {
|
|
2844
2844
|
c.header("Accept-Ranges", "bytes");
|
|
2845
2845
|
c.header("Date", stats.birthtime.toUTCString());
|
|
@@ -2850,16 +2850,334 @@ var serveStatic = (options = { root: "" }) => {
|
|
|
2850
2850
|
end = size - 1;
|
|
2851
2851
|
}
|
|
2852
2852
|
const chunksize = end - start + 1;
|
|
2853
|
-
const stream = createReadStream(
|
|
2853
|
+
const stream = createReadStream(path5, { start, end });
|
|
2854
2854
|
c.header("Content-Length", chunksize.toString());
|
|
2855
2855
|
c.header("Content-Range", `bytes ${start}-${end}/${stats.size}`);
|
|
2856
2856
|
result = c.body(createStreamBody(stream), 206);
|
|
2857
2857
|
}
|
|
2858
|
-
await options.onFound?.(
|
|
2858
|
+
await options.onFound?.(path5, c);
|
|
2859
2859
|
return result;
|
|
2860
2860
|
};
|
|
2861
2861
|
};
|
|
2862
2862
|
|
|
2863
|
+
// src/metadata/tag-colors.ts
|
|
2864
|
+
var TAG_COLORS = [
|
|
2865
|
+
"yellow",
|
|
2866
|
+
"orange",
|
|
2867
|
+
"red",
|
|
2868
|
+
"magenta",
|
|
2869
|
+
"violet",
|
|
2870
|
+
"blue",
|
|
2871
|
+
"cyan",
|
|
2872
|
+
"green"
|
|
2873
|
+
];
|
|
2874
|
+
function isColorToken(value) {
|
|
2875
|
+
return typeof value === "string" && TAG_COLORS.includes(value);
|
|
2876
|
+
}
|
|
2877
|
+
|
|
2878
|
+
// src/archive/chat-id.ts
|
|
2879
|
+
import crypto3 from "crypto";
|
|
2880
|
+
var CROCKFORD_ALPHABET = "0123456789abcdefghjkmnpqrstvwxyz";
|
|
2881
|
+
var CHAT_ID_LENGTH = 6;
|
|
2882
|
+
var MAX_RETRIES = 5;
|
|
2883
|
+
var CHAT_ID_PREFIX = "clog_";
|
|
2884
|
+
var WIRE_FORM_RE = new RegExp(
|
|
2885
|
+
`^${CHAT_ID_PREFIX}[${CROCKFORD_ALPHABET}]{${CHAT_ID_LENGTH}}$`
|
|
2886
|
+
);
|
|
2887
|
+
function formatChatId(code) {
|
|
2888
|
+
return `${CHAT_ID_PREFIX}${code}`;
|
|
2889
|
+
}
|
|
2890
|
+
function parseChatId(wire) {
|
|
2891
|
+
if (!WIRE_FORM_RE.test(wire)) return null;
|
|
2892
|
+
return wire.slice(CHAT_ID_PREFIX.length);
|
|
2893
|
+
}
|
|
2894
|
+
function generateChatId({
|
|
2895
|
+
isTaken,
|
|
2896
|
+
randomIndex = () => crypto3.randomInt(CROCKFORD_ALPHABET.length)
|
|
2897
|
+
}) {
|
|
2898
|
+
for (let attempt = 0; attempt <= MAX_RETRIES; attempt++) {
|
|
2899
|
+
let code = "";
|
|
2900
|
+
for (let i = 0; i < CHAT_ID_LENGTH; i++) {
|
|
2901
|
+
code += CROCKFORD_ALPHABET[randomIndex()];
|
|
2902
|
+
}
|
|
2903
|
+
if (!isTaken(code)) {
|
|
2904
|
+
return code;
|
|
2905
|
+
}
|
|
2906
|
+
}
|
|
2907
|
+
throw new Error(
|
|
2908
|
+
`Failed to generate unique chat_id after ${MAX_RETRIES + 1} attempts`
|
|
2909
|
+
);
|
|
2910
|
+
}
|
|
2911
|
+
|
|
2912
|
+
// src/visibility.ts
|
|
2913
|
+
function loadChatVisibility(metadata2, opts) {
|
|
2914
|
+
const deleted = metadata2.listDeleted();
|
|
2915
|
+
const trashed = new Set(deleted.map((r) => r.id));
|
|
2916
|
+
const deletedAtById = new Map(
|
|
2917
|
+
deleted.map((r) => [r.id, r.deletedAt?.getTime() ?? null])
|
|
2918
|
+
);
|
|
2919
|
+
const showTrashed = opts.includeTrashed === true;
|
|
2920
|
+
return {
|
|
2921
|
+
isTrashed: (internalId) => trashed.has(internalId),
|
|
2922
|
+
isVisible: (internalId) => showTrashed || !trashed.has(internalId),
|
|
2923
|
+
deletedAt: (internalId) => deletedAtById.get(internalId) ?? null
|
|
2924
|
+
};
|
|
2925
|
+
}
|
|
2926
|
+
|
|
2927
|
+
// src/chat-reader.ts
|
|
2928
|
+
function toApiBlock(block) {
|
|
2929
|
+
if (block.type === "tool_result") {
|
|
2930
|
+
return {
|
|
2931
|
+
type: "tool_result",
|
|
2932
|
+
tool_use_id: String(block.toolUseId ?? ""),
|
|
2933
|
+
content: block.content
|
|
2934
|
+
};
|
|
2935
|
+
}
|
|
2936
|
+
return block;
|
|
2937
|
+
}
|
|
2938
|
+
function createChatReader({
|
|
2939
|
+
archive: archive2,
|
|
2940
|
+
metadata: metadata2,
|
|
2941
|
+
tags: tags3
|
|
2942
|
+
}) {
|
|
2943
|
+
function findChat(id) {
|
|
2944
|
+
const code = parseChatId(id);
|
|
2945
|
+
if (code === null) return null;
|
|
2946
|
+
return archive2.read.findChatByChatId(code);
|
|
2947
|
+
}
|
|
2948
|
+
function deriveTitle(customTitle, firstUserText) {
|
|
2949
|
+
if (customTitle && customTitle.trim()) return customTitle;
|
|
2950
|
+
const text2 = firstUserText?.trim().split("\n")[0]?.trim();
|
|
2951
|
+
return text2 && text2.length > 0 ? text2 : "Untitled";
|
|
2952
|
+
}
|
|
2953
|
+
function key(agent, sourceId) {
|
|
2954
|
+
return [agent, sourceId].join("\0");
|
|
2955
|
+
}
|
|
2956
|
+
function listChats({
|
|
2957
|
+
includeTrashed,
|
|
2958
|
+
projects,
|
|
2959
|
+
tags: tagSelection
|
|
2960
|
+
}) {
|
|
2961
|
+
const visibility = loadChatVisibility(metadata2, { includeTrashed });
|
|
2962
|
+
const rows = archive2.read.listChatRows(projects ? { projects } : void 0);
|
|
2963
|
+
let passesTagFilter = null;
|
|
2964
|
+
if (tagSelection) {
|
|
2965
|
+
const realTagIds = tagSelection.filter((t) => t !== "");
|
|
2966
|
+
const wantUntagged = tagSelection.includes("");
|
|
2967
|
+
const allowedByTags = realTagIds.length > 0 ? new Set(tags3.listChatIdsWithAllTags(realTagIds)) : null;
|
|
2968
|
+
const taggedChatIds = wantUntagged ? new Set(tags3.listTagsByChat().keys()) : null;
|
|
2969
|
+
passesTagFilter = (chatInternalId) => {
|
|
2970
|
+
if (allowedByTags && !allowedByTags.has(chatInternalId)) return false;
|
|
2971
|
+
if (taggedChatIds && taggedChatIds.has(chatInternalId)) return false;
|
|
2972
|
+
return true;
|
|
2973
|
+
};
|
|
2974
|
+
}
|
|
2975
|
+
const tsRangeByKey = new Map(
|
|
2976
|
+
archive2.read.listChatTsRanges().map((r) => [key(r.agent, r.sourceId), r])
|
|
2977
|
+
);
|
|
2978
|
+
const sourcePathByKey = new Map(
|
|
2979
|
+
archive2.read.listLatestRawSourcePaths().map((r) => [key(r.agent, r.sourceId), r.sourcePath])
|
|
2980
|
+
);
|
|
2981
|
+
const firstUserTextByKey = new Map(
|
|
2982
|
+
archive2.read.listFirstUserTexts().map((r) => [key(r.agent, r.sourceId), r.text])
|
|
2983
|
+
);
|
|
2984
|
+
const customTitleById = metadata2.listCustomTitles();
|
|
2985
|
+
const tagsByChatId = tags3.listTagsByChat();
|
|
2986
|
+
const chats2 = [];
|
|
2987
|
+
for (const row of rows) {
|
|
2988
|
+
if (!visibility.isVisible(row.id)) continue;
|
|
2989
|
+
if (passesTagFilter && !passesTagFilter(row.id)) continue;
|
|
2990
|
+
const isDeleted = visibility.isTrashed(row.id);
|
|
2991
|
+
const rowKey = key(row.agent, row.sourceId);
|
|
2992
|
+
const tsRange = tsRangeByKey.get(rowKey);
|
|
2993
|
+
const firstSeenAtMs = row.firstSeenAt.getTime();
|
|
2994
|
+
const chat = {
|
|
2995
|
+
id: formatChatId(row.chatId),
|
|
2996
|
+
sourceId: row.sourceId,
|
|
2997
|
+
agent: row.agent,
|
|
2998
|
+
title: deriveTitle(
|
|
2999
|
+
customTitleById.get(row.id),
|
|
3000
|
+
firstUserTextByKey.get(rowKey)
|
|
3001
|
+
),
|
|
3002
|
+
project: row.project ?? "",
|
|
3003
|
+
projectPath: row.projectPath ?? null,
|
|
3004
|
+
sourceFilePath: sourcePathByKey.get(rowKey) ?? null,
|
|
3005
|
+
createdAt: tsRange?.minTs ?? firstSeenAtMs,
|
|
3006
|
+
updatedAt: tsRange?.maxTs ?? firstSeenAtMs,
|
|
3007
|
+
deletedAt: visibility.deletedAt(row.id),
|
|
3008
|
+
tags: tagsByChatId.get(row.id) ?? []
|
|
3009
|
+
};
|
|
3010
|
+
if (isDeleted) chat.isDeleted = true;
|
|
3011
|
+
chats2.push(chat);
|
|
3012
|
+
}
|
|
3013
|
+
return chats2;
|
|
3014
|
+
}
|
|
3015
|
+
function getMessages(id, { includeTrashed }) {
|
|
3016
|
+
const row = findChat(id);
|
|
3017
|
+
if (!row) return null;
|
|
3018
|
+
const visibility = loadChatVisibility(metadata2, { includeTrashed });
|
|
3019
|
+
if (!visibility.isVisible(row.id)) return null;
|
|
3020
|
+
const rows = archive2.read.listMessagesByChat(row.agent, row.sourceId);
|
|
3021
|
+
return rows.map((m) => ({
|
|
3022
|
+
role: m.role,
|
|
3023
|
+
content: m.blocks.map(toApiBlock),
|
|
3024
|
+
timestamp: m.ts.toISOString()
|
|
3025
|
+
}));
|
|
3026
|
+
}
|
|
3027
|
+
return { listChats, getMessages, findChat };
|
|
3028
|
+
}
|
|
3029
|
+
|
|
3030
|
+
// src/app.ts
|
|
3031
|
+
function createApp({ archive: archive2, metadata: metadata2, tags: tags3, webDistDir: webDistDir2 }) {
|
|
3032
|
+
const app2 = new Hono2();
|
|
3033
|
+
const reader = createChatReader({ archive: archive2, metadata: metadata2, tags: tags3 });
|
|
3034
|
+
app2.get("/api/chats", (c) => {
|
|
3035
|
+
const projects = c.req.queries("project");
|
|
3036
|
+
const tagsParam = c.req.query("tags");
|
|
3037
|
+
const tags4 = tagsParam === void 0 ? void 0 : tagsParam.split(",");
|
|
3038
|
+
const chats2 = reader.listChats({
|
|
3039
|
+
includeTrashed: c.req.query("includeTrashed") === "true",
|
|
3040
|
+
projects,
|
|
3041
|
+
tags: tags4
|
|
3042
|
+
});
|
|
3043
|
+
return c.json({ chats: chats2 });
|
|
3044
|
+
});
|
|
3045
|
+
app2.delete("/api/chats/:id", (c) => {
|
|
3046
|
+
const row = reader.findChat(c.req.param("id"));
|
|
3047
|
+
if (!row) {
|
|
3048
|
+
return c.json({ error: "Chat not found" }, 404);
|
|
3049
|
+
}
|
|
3050
|
+
metadata2.softDelete(row.id);
|
|
3051
|
+
return c.body(null, 204);
|
|
3052
|
+
});
|
|
3053
|
+
app2.post("/api/chats/:id/restore", (c) => {
|
|
3054
|
+
const row = reader.findChat(c.req.param("id"));
|
|
3055
|
+
if (!row) {
|
|
3056
|
+
return c.json({ error: "Chat not found" }, 404);
|
|
3057
|
+
}
|
|
3058
|
+
metadata2.restore(row.id);
|
|
3059
|
+
return c.body(null, 204);
|
|
3060
|
+
});
|
|
3061
|
+
app2.patch("/api/chats/:id/title", async (c) => {
|
|
3062
|
+
const row = reader.findChat(c.req.param("id"));
|
|
3063
|
+
if (!row) {
|
|
3064
|
+
return c.json({ error: "Chat not found" }, 404);
|
|
3065
|
+
}
|
|
3066
|
+
let body;
|
|
3067
|
+
try {
|
|
3068
|
+
body = await c.req.json();
|
|
3069
|
+
} catch {
|
|
3070
|
+
return c.json({ error: "Invalid JSON body" }, 400);
|
|
3071
|
+
}
|
|
3072
|
+
if (!body || typeof body !== "object" || typeof body.title !== "string") {
|
|
3073
|
+
return c.json({ error: "Invalid title" }, 400);
|
|
3074
|
+
}
|
|
3075
|
+
const raw2 = body.title;
|
|
3076
|
+
if (raw2.length > 200) {
|
|
3077
|
+
return c.json({ error: "Title too long" }, 400);
|
|
3078
|
+
}
|
|
3079
|
+
const trimmed = raw2.trim();
|
|
3080
|
+
metadata2.setCustomTitle(row.id, trimmed.length > 0 ? trimmed : null);
|
|
3081
|
+
return c.body(null, 204);
|
|
3082
|
+
});
|
|
3083
|
+
app2.get("/api/chats/:id", (c) => {
|
|
3084
|
+
const messages2 = reader.getMessages(c.req.param("id"), {
|
|
3085
|
+
includeTrashed: c.req.query("includeTrashed") === "true"
|
|
3086
|
+
});
|
|
3087
|
+
if (messages2 === null) {
|
|
3088
|
+
return c.json({ error: "Chat not found" }, 404);
|
|
3089
|
+
}
|
|
3090
|
+
return c.json({ messages: messages2 });
|
|
3091
|
+
});
|
|
3092
|
+
app2.get("/api/tags", (c) => {
|
|
3093
|
+
return c.json({ tags: tags3.listTags() });
|
|
3094
|
+
});
|
|
3095
|
+
app2.post("/api/tags", async (c) => {
|
|
3096
|
+
let body;
|
|
3097
|
+
try {
|
|
3098
|
+
body = await c.req.json();
|
|
3099
|
+
} catch {
|
|
3100
|
+
return c.json({ error: "Invalid JSON body" }, 400);
|
|
3101
|
+
}
|
|
3102
|
+
const name = body && typeof body === "object" ? body.name : void 0;
|
|
3103
|
+
const color = body && typeof body === "object" ? body.color : void 0;
|
|
3104
|
+
if (typeof name !== "string" || name.trim().length === 0) {
|
|
3105
|
+
return c.json({ error: "Invalid name" }, 400);
|
|
3106
|
+
}
|
|
3107
|
+
if (!isColorToken(color)) {
|
|
3108
|
+
return c.json({ error: "Invalid color" }, 400);
|
|
3109
|
+
}
|
|
3110
|
+
const tag = tags3.createTag(name.trim(), color);
|
|
3111
|
+
return c.json({ tag }, 201);
|
|
3112
|
+
});
|
|
3113
|
+
app2.patch("/api/tags/:id", async (c) => {
|
|
3114
|
+
const id = c.req.param("id");
|
|
3115
|
+
if (!tags3.getTag(id)) {
|
|
3116
|
+
return c.json({ error: "Tag not found" }, 404);
|
|
3117
|
+
}
|
|
3118
|
+
let body;
|
|
3119
|
+
try {
|
|
3120
|
+
body = await c.req.json();
|
|
3121
|
+
} catch {
|
|
3122
|
+
return c.json({ error: "Invalid JSON body" }, 400);
|
|
3123
|
+
}
|
|
3124
|
+
const name = body && typeof body === "object" ? body.name : void 0;
|
|
3125
|
+
const color = body && typeof body === "object" ? body.color : void 0;
|
|
3126
|
+
if (name !== void 0) {
|
|
3127
|
+
if (typeof name !== "string" || name.trim().length === 0) {
|
|
3128
|
+
return c.json({ error: "Invalid name" }, 400);
|
|
3129
|
+
}
|
|
3130
|
+
}
|
|
3131
|
+
if (color !== void 0 && !isColorToken(color)) {
|
|
3132
|
+
return c.json({ error: "Invalid color" }, 400);
|
|
3133
|
+
}
|
|
3134
|
+
if (typeof name === "string") tags3.renameTag(id, name.trim());
|
|
3135
|
+
if (isColorToken(color)) tags3.recolorTag(id, color);
|
|
3136
|
+
return c.body(null, 204);
|
|
3137
|
+
});
|
|
3138
|
+
app2.delete("/api/tags/:id", (c) => {
|
|
3139
|
+
if (!tags3.getTag(c.req.param("id"))) {
|
|
3140
|
+
return c.json({ error: "Tag not found" }, 404);
|
|
3141
|
+
}
|
|
3142
|
+
const result = tags3.deleteTag(c.req.param("id"));
|
|
3143
|
+
return c.json(result);
|
|
3144
|
+
});
|
|
3145
|
+
app2.post("/api/chats/:id/tags", async (c) => {
|
|
3146
|
+
const row = reader.findChat(c.req.param("id"));
|
|
3147
|
+
if (!row) {
|
|
3148
|
+
return c.json({ error: "Chat not found" }, 404);
|
|
3149
|
+
}
|
|
3150
|
+
let body;
|
|
3151
|
+
try {
|
|
3152
|
+
body = await c.req.json();
|
|
3153
|
+
} catch {
|
|
3154
|
+
return c.json({ error: "Invalid JSON body" }, 400);
|
|
3155
|
+
}
|
|
3156
|
+
const tagId = body && typeof body === "object" ? body.tagId : void 0;
|
|
3157
|
+
if (typeof tagId !== "string" || !tags3.getTag(tagId)) {
|
|
3158
|
+
return c.json({ error: "Tag not found" }, 404);
|
|
3159
|
+
}
|
|
3160
|
+
tags3.assignTag(row.id, tagId);
|
|
3161
|
+
return c.body(null, 204);
|
|
3162
|
+
});
|
|
3163
|
+
app2.delete("/api/chats/:id/tags/:tagId", (c) => {
|
|
3164
|
+
const row = reader.findChat(c.req.param("id"));
|
|
3165
|
+
if (!row) {
|
|
3166
|
+
return c.json({ error: "Chat not found" }, 404);
|
|
3167
|
+
}
|
|
3168
|
+
tags3.removeTag(row.id, c.req.param("tagId"));
|
|
3169
|
+
return c.body(null, 204);
|
|
3170
|
+
});
|
|
3171
|
+
if (webDistDir2) {
|
|
3172
|
+
app2.use("*", serveStatic({ root: webDistDir2 }));
|
|
3173
|
+
app2.use("*", serveStatic({ root: webDistDir2, path: "index.html" }));
|
|
3174
|
+
}
|
|
3175
|
+
return app2;
|
|
3176
|
+
}
|
|
3177
|
+
|
|
3178
|
+
// src/archive/repository.ts
|
|
3179
|
+
import crypto5 from "crypto";
|
|
3180
|
+
|
|
2863
3181
|
// ../node_modules/.pnpm/drizzle-orm@0.45.2_@types+better-sqlite3@7.6.13_better-sqlite3@12.9.0/node_modules/drizzle-orm/entity.js
|
|
2864
3182
|
var entityKind = /* @__PURE__ */ Symbol.for("drizzle:entityKind");
|
|
2865
3183
|
function is(value, type) {
|
|
@@ -4173,7 +4491,7 @@ var QueryPromise = class {
|
|
|
4173
4491
|
function mapResultRow(columns, row, joinsNotNullableMap) {
|
|
4174
4492
|
const nullifyMap = {};
|
|
4175
4493
|
const result = columns.reduce(
|
|
4176
|
-
(result2, { path:
|
|
4494
|
+
(result2, { path: path5, field }, columnIndex) => {
|
|
4177
4495
|
let decoder;
|
|
4178
4496
|
if (is(field, Column)) {
|
|
4179
4497
|
decoder = field;
|
|
@@ -4185,8 +4503,8 @@ function mapResultRow(columns, row, joinsNotNullableMap) {
|
|
|
4185
4503
|
decoder = field.sql.decoder;
|
|
4186
4504
|
}
|
|
4187
4505
|
let node = result2;
|
|
4188
|
-
for (const [pathChunkIndex, pathChunk] of
|
|
4189
|
-
if (pathChunkIndex <
|
|
4506
|
+
for (const [pathChunkIndex, pathChunk] of path5.entries()) {
|
|
4507
|
+
if (pathChunkIndex < path5.length - 1) {
|
|
4190
4508
|
if (!(pathChunk in node)) {
|
|
4191
4509
|
node[pathChunk] = {};
|
|
4192
4510
|
}
|
|
@@ -4194,8 +4512,8 @@ function mapResultRow(columns, row, joinsNotNullableMap) {
|
|
|
4194
4512
|
} else {
|
|
4195
4513
|
const rawValue = row[columnIndex];
|
|
4196
4514
|
const value = node[pathChunk] = rawValue === null ? null : decoder.mapFromDriverValue(rawValue);
|
|
4197
|
-
if (joinsNotNullableMap && is(field, Column) &&
|
|
4198
|
-
const objectName =
|
|
4515
|
+
if (joinsNotNullableMap && is(field, Column) && path5.length === 2) {
|
|
4516
|
+
const objectName = path5[0];
|
|
4199
4517
|
if (!(objectName in nullifyMap)) {
|
|
4200
4518
|
nullifyMap[objectName] = value === null ? getTableName(field.table) : false;
|
|
4201
4519
|
} else if (typeof nullifyMap[objectName] === "string" && nullifyMap[objectName] !== getTableName(field.table)) {
|
|
@@ -4239,8 +4557,8 @@ function haveSameKeys(left, right) {
|
|
|
4239
4557
|
if (leftKeys.length !== rightKeys.length) {
|
|
4240
4558
|
return false;
|
|
4241
4559
|
}
|
|
4242
|
-
for (const [
|
|
4243
|
-
if (key !== rightKeys[
|
|
4560
|
+
for (const [index2, key] of leftKeys.entries()) {
|
|
4561
|
+
if (key !== rightKeys[index2]) {
|
|
4244
4562
|
return false;
|
|
4245
4563
|
}
|
|
4246
4564
|
}
|
|
@@ -4620,19 +4938,19 @@ function extractTablesRelationalConfig(schema, configHelpers) {
|
|
|
4620
4938
|
const relations2 = value.config(
|
|
4621
4939
|
configHelpers(value.table)
|
|
4622
4940
|
);
|
|
4623
|
-
let
|
|
4941
|
+
let primaryKey2;
|
|
4624
4942
|
for (const [relationName, relation] of Object.entries(relations2)) {
|
|
4625
4943
|
if (tableName) {
|
|
4626
4944
|
const tableConfig = tablesConfig[tableName];
|
|
4627
4945
|
tableConfig.relations[relationName] = relation;
|
|
4628
|
-
if (
|
|
4629
|
-
tableConfig.primaryKey.push(...
|
|
4946
|
+
if (primaryKey2) {
|
|
4947
|
+
tableConfig.primaryKey.push(...primaryKey2);
|
|
4630
4948
|
}
|
|
4631
4949
|
} else {
|
|
4632
4950
|
if (!(dbName in relationsBuffer)) {
|
|
4633
4951
|
relationsBuffer[dbName] = {
|
|
4634
4952
|
relations: {},
|
|
4635
|
-
primaryKey
|
|
4953
|
+
primaryKey: primaryKey2
|
|
4636
4954
|
};
|
|
4637
4955
|
}
|
|
4638
4956
|
relationsBuffer[dbName].relations[relationName] = relation;
|
|
@@ -4754,60 +5072,126 @@ function mapRelationalRow(tablesConfig, tableConfig, row, buildQueryResultSelect
|
|
|
4754
5072
|
return result;
|
|
4755
5073
|
}
|
|
4756
5074
|
|
|
4757
|
-
// src/
|
|
4758
|
-
|
|
4759
|
-
|
|
4760
|
-
|
|
4761
|
-
|
|
4762
|
-
ingestionEvents: () => ingestionEvents,
|
|
4763
|
-
messages: () => messages,
|
|
4764
|
-
rawMessages: () => rawMessages,
|
|
4765
|
-
schemaVersion: () => schemaVersion
|
|
4766
|
-
});
|
|
5075
|
+
// src/storage/openStore.ts
|
|
5076
|
+
import fs2 from "fs";
|
|
5077
|
+
import path from "path";
|
|
5078
|
+
import { fileURLToPath } from "url";
|
|
5079
|
+
import Database from "better-sqlite3";
|
|
4767
5080
|
|
|
4768
|
-
// ../node_modules/.pnpm/drizzle-orm@0.45.2_@types+better-sqlite3@7.6.13_better-sqlite3@12.9.0/node_modules/drizzle-orm/
|
|
4769
|
-
|
|
4770
|
-
|
|
4771
|
-
|
|
4772
|
-
|
|
4773
|
-
|
|
4774
|
-
|
|
4775
|
-
|
|
4776
|
-
|
|
4777
|
-
constructor(config, actions) {
|
|
4778
|
-
this.reference = () => {
|
|
4779
|
-
const { name, columns, foreignColumns } = config();
|
|
4780
|
-
return { name, columns, foreignTable: foreignColumns[0].table, foreignColumns };
|
|
4781
|
-
};
|
|
4782
|
-
if (actions) {
|
|
4783
|
-
this._onUpdate = actions.onUpdate;
|
|
4784
|
-
this._onDelete = actions.onDelete;
|
|
4785
|
-
}
|
|
4786
|
-
}
|
|
4787
|
-
onUpdate(action2) {
|
|
4788
|
-
this._onUpdate = action2;
|
|
4789
|
-
return this;
|
|
4790
|
-
}
|
|
4791
|
-
onDelete(action2) {
|
|
4792
|
-
this._onDelete = action2;
|
|
4793
|
-
return this;
|
|
4794
|
-
}
|
|
4795
|
-
/** @internal */
|
|
4796
|
-
build(table) {
|
|
4797
|
-
return new ForeignKey2(table, this);
|
|
4798
|
-
}
|
|
4799
|
-
};
|
|
4800
|
-
var ForeignKey2 = class {
|
|
4801
|
-
constructor(table, builder) {
|
|
4802
|
-
this.table = table;
|
|
4803
|
-
this.reference = builder.reference;
|
|
4804
|
-
this.onUpdate = builder._onUpdate;
|
|
4805
|
-
this.onDelete = builder._onDelete;
|
|
5081
|
+
// ../node_modules/.pnpm/drizzle-orm@0.45.2_@types+better-sqlite3@7.6.13_better-sqlite3@12.9.0/node_modules/drizzle-orm/better-sqlite3/driver.js
|
|
5082
|
+
import Client from "better-sqlite3";
|
|
5083
|
+
|
|
5084
|
+
// ../node_modules/.pnpm/drizzle-orm@0.45.2_@types+better-sqlite3@7.6.13_better-sqlite3@12.9.0/node_modules/drizzle-orm/selection-proxy.js
|
|
5085
|
+
var SelectionProxyHandler = class _SelectionProxyHandler {
|
|
5086
|
+
static [entityKind] = "SelectionProxyHandler";
|
|
5087
|
+
config;
|
|
5088
|
+
constructor(config) {
|
|
5089
|
+
this.config = { ...config };
|
|
4806
5090
|
}
|
|
4807
|
-
|
|
4808
|
-
|
|
4809
|
-
|
|
4810
|
-
|
|
5091
|
+
get(subquery, prop) {
|
|
5092
|
+
if (prop === "_") {
|
|
5093
|
+
return {
|
|
5094
|
+
...subquery["_"],
|
|
5095
|
+
selectedFields: new Proxy(
|
|
5096
|
+
subquery._.selectedFields,
|
|
5097
|
+
this
|
|
5098
|
+
)
|
|
5099
|
+
};
|
|
5100
|
+
}
|
|
5101
|
+
if (prop === ViewBaseConfig) {
|
|
5102
|
+
return {
|
|
5103
|
+
...subquery[ViewBaseConfig],
|
|
5104
|
+
selectedFields: new Proxy(
|
|
5105
|
+
subquery[ViewBaseConfig].selectedFields,
|
|
5106
|
+
this
|
|
5107
|
+
)
|
|
5108
|
+
};
|
|
5109
|
+
}
|
|
5110
|
+
if (typeof prop === "symbol") {
|
|
5111
|
+
return subquery[prop];
|
|
5112
|
+
}
|
|
5113
|
+
const columns = is(subquery, Subquery) ? subquery._.selectedFields : is(subquery, View) ? subquery[ViewBaseConfig].selectedFields : subquery;
|
|
5114
|
+
const value = columns[prop];
|
|
5115
|
+
if (is(value, SQL.Aliased)) {
|
|
5116
|
+
if (this.config.sqlAliasedBehavior === "sql" && !value.isSelectionField) {
|
|
5117
|
+
return value.sql;
|
|
5118
|
+
}
|
|
5119
|
+
const newValue = value.clone();
|
|
5120
|
+
newValue.isSelectionField = true;
|
|
5121
|
+
return newValue;
|
|
5122
|
+
}
|
|
5123
|
+
if (is(value, SQL)) {
|
|
5124
|
+
if (this.config.sqlBehavior === "sql") {
|
|
5125
|
+
return value;
|
|
5126
|
+
}
|
|
5127
|
+
throw new Error(
|
|
5128
|
+
`You tried to reference "${prop}" field from a subquery, which is a raw SQL field, but it doesn't have an alias declared. Please add an alias to the field using ".as('alias')" method.`
|
|
5129
|
+
);
|
|
5130
|
+
}
|
|
5131
|
+
if (is(value, Column)) {
|
|
5132
|
+
if (this.config.alias) {
|
|
5133
|
+
return new Proxy(
|
|
5134
|
+
value,
|
|
5135
|
+
new ColumnAliasProxyHandler(
|
|
5136
|
+
new Proxy(
|
|
5137
|
+
value.table,
|
|
5138
|
+
new TableAliasProxyHandler(this.config.alias, this.config.replaceOriginalName ?? false)
|
|
5139
|
+
)
|
|
5140
|
+
)
|
|
5141
|
+
);
|
|
5142
|
+
}
|
|
5143
|
+
return value;
|
|
5144
|
+
}
|
|
5145
|
+
if (typeof value !== "object" || value === null) {
|
|
5146
|
+
return value;
|
|
5147
|
+
}
|
|
5148
|
+
return new Proxy(value, new _SelectionProxyHandler(this.config));
|
|
5149
|
+
}
|
|
5150
|
+
};
|
|
5151
|
+
|
|
5152
|
+
// ../node_modules/.pnpm/drizzle-orm@0.45.2_@types+better-sqlite3@7.6.13_better-sqlite3@12.9.0/node_modules/drizzle-orm/sqlite-core/foreign-keys.js
|
|
5153
|
+
var ForeignKeyBuilder2 = class {
|
|
5154
|
+
static [entityKind] = "SQLiteForeignKeyBuilder";
|
|
5155
|
+
/** @internal */
|
|
5156
|
+
reference;
|
|
5157
|
+
/** @internal */
|
|
5158
|
+
_onUpdate;
|
|
5159
|
+
/** @internal */
|
|
5160
|
+
_onDelete;
|
|
5161
|
+
constructor(config, actions) {
|
|
5162
|
+
this.reference = () => {
|
|
5163
|
+
const { name, columns, foreignColumns } = config();
|
|
5164
|
+
return { name, columns, foreignTable: foreignColumns[0].table, foreignColumns };
|
|
5165
|
+
};
|
|
5166
|
+
if (actions) {
|
|
5167
|
+
this._onUpdate = actions.onUpdate;
|
|
5168
|
+
this._onDelete = actions.onDelete;
|
|
5169
|
+
}
|
|
5170
|
+
}
|
|
5171
|
+
onUpdate(action2) {
|
|
5172
|
+
this._onUpdate = action2;
|
|
5173
|
+
return this;
|
|
5174
|
+
}
|
|
5175
|
+
onDelete(action2) {
|
|
5176
|
+
this._onDelete = action2;
|
|
5177
|
+
return this;
|
|
5178
|
+
}
|
|
5179
|
+
/** @internal */
|
|
5180
|
+
build(table) {
|
|
5181
|
+
return new ForeignKey2(table, this);
|
|
5182
|
+
}
|
|
5183
|
+
};
|
|
5184
|
+
var ForeignKey2 = class {
|
|
5185
|
+
constructor(table, builder) {
|
|
5186
|
+
this.table = table;
|
|
5187
|
+
this.reference = builder.reference;
|
|
5188
|
+
this.onUpdate = builder._onUpdate;
|
|
5189
|
+
this.onDelete = builder._onDelete;
|
|
5190
|
+
}
|
|
5191
|
+
static [entityKind] = "SQLiteForeignKey";
|
|
5192
|
+
reference;
|
|
5193
|
+
onUpdate;
|
|
5194
|
+
onDelete;
|
|
4811
5195
|
getName() {
|
|
4812
5196
|
const { name, columns, foreignColumns } = this.reference();
|
|
4813
5197
|
const columnNames = columns.map((column) => column.name);
|
|
@@ -5317,74 +5701,6 @@ function text(a, b = {}) {
|
|
|
5317
5701
|
return new SQLiteTextBuilder(name, config);
|
|
5318
5702
|
}
|
|
5319
5703
|
|
|
5320
|
-
// ../node_modules/.pnpm/drizzle-orm@0.45.2_@types+better-sqlite3@7.6.13_better-sqlite3@12.9.0/node_modules/drizzle-orm/selection-proxy.js
|
|
5321
|
-
var SelectionProxyHandler = class _SelectionProxyHandler {
|
|
5322
|
-
static [entityKind] = "SelectionProxyHandler";
|
|
5323
|
-
config;
|
|
5324
|
-
constructor(config) {
|
|
5325
|
-
this.config = { ...config };
|
|
5326
|
-
}
|
|
5327
|
-
get(subquery, prop) {
|
|
5328
|
-
if (prop === "_") {
|
|
5329
|
-
return {
|
|
5330
|
-
...subquery["_"],
|
|
5331
|
-
selectedFields: new Proxy(
|
|
5332
|
-
subquery._.selectedFields,
|
|
5333
|
-
this
|
|
5334
|
-
)
|
|
5335
|
-
};
|
|
5336
|
-
}
|
|
5337
|
-
if (prop === ViewBaseConfig) {
|
|
5338
|
-
return {
|
|
5339
|
-
...subquery[ViewBaseConfig],
|
|
5340
|
-
selectedFields: new Proxy(
|
|
5341
|
-
subquery[ViewBaseConfig].selectedFields,
|
|
5342
|
-
this
|
|
5343
|
-
)
|
|
5344
|
-
};
|
|
5345
|
-
}
|
|
5346
|
-
if (typeof prop === "symbol") {
|
|
5347
|
-
return subquery[prop];
|
|
5348
|
-
}
|
|
5349
|
-
const columns = is(subquery, Subquery) ? subquery._.selectedFields : is(subquery, View) ? subquery[ViewBaseConfig].selectedFields : subquery;
|
|
5350
|
-
const value = columns[prop];
|
|
5351
|
-
if (is(value, SQL.Aliased)) {
|
|
5352
|
-
if (this.config.sqlAliasedBehavior === "sql" && !value.isSelectionField) {
|
|
5353
|
-
return value.sql;
|
|
5354
|
-
}
|
|
5355
|
-
const newValue = value.clone();
|
|
5356
|
-
newValue.isSelectionField = true;
|
|
5357
|
-
return newValue;
|
|
5358
|
-
}
|
|
5359
|
-
if (is(value, SQL)) {
|
|
5360
|
-
if (this.config.sqlBehavior === "sql") {
|
|
5361
|
-
return value;
|
|
5362
|
-
}
|
|
5363
|
-
throw new Error(
|
|
5364
|
-
`You tried to reference "${prop}" field from a subquery, which is a raw SQL field, but it doesn't have an alias declared. Please add an alias to the field using ".as('alias')" method.`
|
|
5365
|
-
);
|
|
5366
|
-
}
|
|
5367
|
-
if (is(value, Column)) {
|
|
5368
|
-
if (this.config.alias) {
|
|
5369
|
-
return new Proxy(
|
|
5370
|
-
value,
|
|
5371
|
-
new ColumnAliasProxyHandler(
|
|
5372
|
-
new Proxy(
|
|
5373
|
-
value.table,
|
|
5374
|
-
new TableAliasProxyHandler(this.config.alias, this.config.replaceOriginalName ?? false)
|
|
5375
|
-
)
|
|
5376
|
-
)
|
|
5377
|
-
);
|
|
5378
|
-
}
|
|
5379
|
-
return value;
|
|
5380
|
-
}
|
|
5381
|
-
if (typeof value !== "object" || value === null) {
|
|
5382
|
-
return value;
|
|
5383
|
-
}
|
|
5384
|
-
return new Proxy(value, new _SelectionProxyHandler(this.config));
|
|
5385
|
-
}
|
|
5386
|
-
};
|
|
5387
|
-
|
|
5388
5704
|
// ../node_modules/.pnpm/drizzle-orm@0.45.2_@types+better-sqlite3@7.6.13_better-sqlite3@12.9.0/node_modules/drizzle-orm/sqlite-core/columns/all.js
|
|
5389
5705
|
function getSQLiteColumnBuilders() {
|
|
5390
5706
|
return {
|
|
@@ -5478,10 +5794,49 @@ var Index = class {
|
|
|
5478
5794
|
this.config = { ...config, table };
|
|
5479
5795
|
}
|
|
5480
5796
|
};
|
|
5797
|
+
function index(name) {
|
|
5798
|
+
return new IndexBuilderOn(name, false);
|
|
5799
|
+
}
|
|
5481
5800
|
function uniqueIndex(name) {
|
|
5482
5801
|
return new IndexBuilderOn(name, true);
|
|
5483
5802
|
}
|
|
5484
5803
|
|
|
5804
|
+
// ../node_modules/.pnpm/drizzle-orm@0.45.2_@types+better-sqlite3@7.6.13_better-sqlite3@12.9.0/node_modules/drizzle-orm/sqlite-core/primary-keys.js
|
|
5805
|
+
function primaryKey(...config) {
|
|
5806
|
+
if (config[0].columns) {
|
|
5807
|
+
return new PrimaryKeyBuilder2(config[0].columns, config[0].name);
|
|
5808
|
+
}
|
|
5809
|
+
return new PrimaryKeyBuilder2(config);
|
|
5810
|
+
}
|
|
5811
|
+
var PrimaryKeyBuilder2 = class {
|
|
5812
|
+
static [entityKind] = "SQLitePrimaryKeyBuilder";
|
|
5813
|
+
/** @internal */
|
|
5814
|
+
columns;
|
|
5815
|
+
/** @internal */
|
|
5816
|
+
name;
|
|
5817
|
+
constructor(columns, name) {
|
|
5818
|
+
this.columns = columns;
|
|
5819
|
+
this.name = name;
|
|
5820
|
+
}
|
|
5821
|
+
/** @internal */
|
|
5822
|
+
build(table) {
|
|
5823
|
+
return new PrimaryKey2(table, this.columns, this.name);
|
|
5824
|
+
}
|
|
5825
|
+
};
|
|
5826
|
+
var PrimaryKey2 = class {
|
|
5827
|
+
constructor(table, columns, name) {
|
|
5828
|
+
this.table = table;
|
|
5829
|
+
this.columns = columns;
|
|
5830
|
+
this.name = name;
|
|
5831
|
+
}
|
|
5832
|
+
static [entityKind] = "SQLitePrimaryKey";
|
|
5833
|
+
columns;
|
|
5834
|
+
name;
|
|
5835
|
+
getName() {
|
|
5836
|
+
return this.name ?? `${this.table[SQLiteTable.Symbol.Name]}_${this.columns.map((column) => column.name).join("_")}_pk`;
|
|
5837
|
+
}
|
|
5838
|
+
};
|
|
5839
|
+
|
|
5485
5840
|
// ../node_modules/.pnpm/drizzle-orm@0.45.2_@types+better-sqlite3@7.6.13_better-sqlite3@12.9.0/node_modules/drizzle-orm/sqlite-core/utils.js
|
|
5486
5841
|
function extractUsedTable(table) {
|
|
5487
5842
|
if (is(table, SQLiteTable)) {
|
|
@@ -5830,8 +6185,8 @@ var SQLiteDialect = class {
|
|
|
5830
6185
|
}
|
|
5831
6186
|
const joinsArray = [];
|
|
5832
6187
|
if (joins) {
|
|
5833
|
-
for (const [
|
|
5834
|
-
if (
|
|
6188
|
+
for (const [index2, joinMeta] of joins.entries()) {
|
|
6189
|
+
if (index2 === 0) {
|
|
5835
6190
|
joinsArray.push(sql` `);
|
|
5836
6191
|
}
|
|
5837
6192
|
const table = joinMeta.table;
|
|
@@ -5851,7 +6206,7 @@ var SQLiteDialect = class {
|
|
|
5851
6206
|
sql`${sql.raw(joinMeta.joinType)} join ${table}${onSql}`
|
|
5852
6207
|
);
|
|
5853
6208
|
}
|
|
5854
|
-
if (
|
|
6209
|
+
if (index2 < joins.length - 1) {
|
|
5855
6210
|
joinsArray.push(sql` `);
|
|
5856
6211
|
}
|
|
5857
6212
|
}
|
|
@@ -5864,9 +6219,9 @@ var SQLiteDialect = class {
|
|
|
5864
6219
|
buildOrderBy(orderBy) {
|
|
5865
6220
|
const orderByList = [];
|
|
5866
6221
|
if (orderBy) {
|
|
5867
|
-
for (const [
|
|
6222
|
+
for (const [index2, orderByValue] of orderBy.entries()) {
|
|
5868
6223
|
orderByList.push(orderByValue);
|
|
5869
|
-
if (
|
|
6224
|
+
if (index2 < orderBy.length - 1) {
|
|
5870
6225
|
orderByList.push(sql`, `);
|
|
5871
6226
|
}
|
|
5872
6227
|
}
|
|
@@ -5919,9 +6274,9 @@ var SQLiteDialect = class {
|
|
|
5919
6274
|
const havingSql = having ? sql` having ${having}` : void 0;
|
|
5920
6275
|
const groupByList = [];
|
|
5921
6276
|
if (groupBy) {
|
|
5922
|
-
for (const [
|
|
6277
|
+
for (const [index2, groupByValue] of groupBy.entries()) {
|
|
5923
6278
|
groupByList.push(groupByValue);
|
|
5924
|
-
if (
|
|
6279
|
+
if (index2 < groupBy.length - 1) {
|
|
5925
6280
|
groupByList.push(sql`, `);
|
|
5926
6281
|
}
|
|
5927
6282
|
}
|
|
@@ -8168,242 +8523,6 @@ var SQLiteTransaction = class extends BaseSQLiteDatabase {
|
|
|
8168
8523
|
}
|
|
8169
8524
|
};
|
|
8170
8525
|
|
|
8171
|
-
// src/archive/schema.ts
|
|
8172
|
-
var archiveMeta = sqliteTable("archive_meta", {
|
|
8173
|
-
id: integer("id").primaryKey(),
|
|
8174
|
-
archiveUuid: text("archive_uuid").notNull(),
|
|
8175
|
-
createdAt: integer("created_at", { mode: "timestamp_ms" }).notNull()
|
|
8176
|
-
});
|
|
8177
|
-
var schemaVersion = sqliteTable("schema_version", {
|
|
8178
|
-
version: integer("version").primaryKey(),
|
|
8179
|
-
appliedAt: integer("applied_at", { mode: "timestamp_ms" }).notNull()
|
|
8180
|
-
});
|
|
8181
|
-
var chats = sqliteTable(
|
|
8182
|
-
"chats",
|
|
8183
|
-
{
|
|
8184
|
-
id: text("id").primaryKey(),
|
|
8185
|
-
chatId: text("chat_id").notNull().unique(),
|
|
8186
|
-
agent: text("agent").notNull(),
|
|
8187
|
-
sourceId: text("source_id").notNull(),
|
|
8188
|
-
firstSeenAt: integer("first_seen_at", { mode: "timestamp_ms" }).notNull(),
|
|
8189
|
-
project: text("project"),
|
|
8190
|
-
projectPath: text("project_path")
|
|
8191
|
-
},
|
|
8192
|
-
(t) => [uniqueIndex("chats_agent_source_idx").on(t.agent, t.sourceId)]
|
|
8193
|
-
);
|
|
8194
|
-
var rawMessages = sqliteTable(
|
|
8195
|
-
"raw_messages",
|
|
8196
|
-
{
|
|
8197
|
-
id: integer("id").primaryKey({ autoIncrement: true }),
|
|
8198
|
-
agent: text("agent").notNull(),
|
|
8199
|
-
sourceId: text("source_id").notNull(),
|
|
8200
|
-
sourcePath: text("source_path").notNull(),
|
|
8201
|
-
sourceLocator: text("source_locator").notNull(),
|
|
8202
|
-
rawPayload: text("raw_payload").notNull(),
|
|
8203
|
-
payloadHash: text("payload_hash").notNull(),
|
|
8204
|
-
ingestedAt: integer("ingested_at", { mode: "timestamp_ms" }).notNull()
|
|
8205
|
-
},
|
|
8206
|
-
(t) => [
|
|
8207
|
-
uniqueIndex("raw_messages_idem_idx").on(t.agent, t.sourceId, t.payloadHash)
|
|
8208
|
-
]
|
|
8209
|
-
);
|
|
8210
|
-
var messages = sqliteTable(
|
|
8211
|
-
"messages",
|
|
8212
|
-
{
|
|
8213
|
-
id: integer("id").primaryKey({ autoIncrement: true }),
|
|
8214
|
-
agent: text("agent").notNull(),
|
|
8215
|
-
sourceId: text("source_id").notNull(),
|
|
8216
|
-
messageId: text("message_id").notNull(),
|
|
8217
|
-
role: text("role").notNull(),
|
|
8218
|
-
ts: integer("ts", { mode: "timestamp_ms" }).notNull(),
|
|
8219
|
-
text: text("text").notNull(),
|
|
8220
|
-
blocks: text("blocks", { mode: "json" }).notNull(),
|
|
8221
|
-
rawId: integer("raw_id").notNull().references(() => rawMessages.id)
|
|
8222
|
-
},
|
|
8223
|
-
(t) => [
|
|
8224
|
-
uniqueIndex("messages_canonical_idx").on(t.agent, t.sourceId, t.messageId)
|
|
8225
|
-
]
|
|
8226
|
-
);
|
|
8227
|
-
var ingestionEvents = sqliteTable("ingestion_events", {
|
|
8228
|
-
id: integer("id").primaryKey({ autoIncrement: true }),
|
|
8229
|
-
agent: text("agent").notNull(),
|
|
8230
|
-
sourceId: text("source_id").notNull(),
|
|
8231
|
-
sourcePath: text("source_path").notNull(),
|
|
8232
|
-
eventType: text("event_type").notNull(),
|
|
8233
|
-
detail: text("detail", { mode: "json" }).notNull(),
|
|
8234
|
-
observedAt: integer("observed_at", { mode: "timestamp_ms" }).notNull()
|
|
8235
|
-
});
|
|
8236
|
-
|
|
8237
|
-
// src/visibility.ts
|
|
8238
|
-
function loadChatVisibility(metadata2, opts) {
|
|
8239
|
-
const deleted = metadata2.listDeleted();
|
|
8240
|
-
const trashed = new Set(deleted.map((r) => r.id));
|
|
8241
|
-
const deletedAtById = new Map(
|
|
8242
|
-
deleted.map((r) => [r.id, r.deletedAt?.getTime() ?? null])
|
|
8243
|
-
);
|
|
8244
|
-
const showTrashed = opts.includeTrashed === true;
|
|
8245
|
-
return {
|
|
8246
|
-
isTrashed: (internalId) => trashed.has(internalId),
|
|
8247
|
-
isVisible: (internalId) => showTrashed || !trashed.has(internalId),
|
|
8248
|
-
deletedAt: (internalId) => deletedAtById.get(internalId) ?? null
|
|
8249
|
-
};
|
|
8250
|
-
}
|
|
8251
|
-
|
|
8252
|
-
// src/app.ts
|
|
8253
|
-
function toApiBlock(block) {
|
|
8254
|
-
if (block.type === "tool_result") {
|
|
8255
|
-
return {
|
|
8256
|
-
type: "tool_result",
|
|
8257
|
-
tool_use_id: String(block.toolUseId ?? ""),
|
|
8258
|
-
content: block.content
|
|
8259
|
-
};
|
|
8260
|
-
}
|
|
8261
|
-
return block;
|
|
8262
|
-
}
|
|
8263
|
-
var CLAUDE_CODE_AGENT = "claude-code";
|
|
8264
|
-
function createApp({ archive: archive2, metadata: metadata2, webDistDir: webDistDir2 }) {
|
|
8265
|
-
const app2 = new Hono2();
|
|
8266
|
-
function findArchiveChatBySourceId(sourceId) {
|
|
8267
|
-
return archive2.db.select().from(chats).where(eq(chats.sourceId, sourceId)).get();
|
|
8268
|
-
}
|
|
8269
|
-
app2.get("/api/chats", (c) => {
|
|
8270
|
-
const visibility = loadChatVisibility(metadata2, {
|
|
8271
|
-
includeTrashed: c.req.query("includeTrashed") === "true"
|
|
8272
|
-
});
|
|
8273
|
-
const rows = archive2.db.select().from(chats).all();
|
|
8274
|
-
const chats2 = [];
|
|
8275
|
-
for (const row of rows) {
|
|
8276
|
-
if (!visibility.isVisible(row.id)) continue;
|
|
8277
|
-
const isDeleted = visibility.isTrashed(row.id);
|
|
8278
|
-
const latestRaw = archive2.db.select({ sourcePath: rawMessages.sourcePath }).from(rawMessages).where(
|
|
8279
|
-
and(
|
|
8280
|
-
eq(rawMessages.agent, CLAUDE_CODE_AGENT),
|
|
8281
|
-
eq(rawMessages.sourceId, row.sourceId)
|
|
8282
|
-
)
|
|
8283
|
-
).orderBy(desc(rawMessages.ingestedAt)).limit(1).get();
|
|
8284
|
-
const tsRange = archive2.db.select({
|
|
8285
|
-
minTs: sql`min(${messages.ts})`,
|
|
8286
|
-
maxTs: sql`max(${messages.ts})`
|
|
8287
|
-
}).from(messages).where(
|
|
8288
|
-
and(
|
|
8289
|
-
eq(messages.agent, CLAUDE_CODE_AGENT),
|
|
8290
|
-
eq(messages.sourceId, row.sourceId)
|
|
8291
|
-
)
|
|
8292
|
-
).get();
|
|
8293
|
-
const firstSeenAtMs = row.firstSeenAt.getTime();
|
|
8294
|
-
const chat = {
|
|
8295
|
-
id: row.sourceId,
|
|
8296
|
-
chatId: row.chatId,
|
|
8297
|
-
agent: row.agent,
|
|
8298
|
-
title: deriveTitle(archive2, metadata2, row),
|
|
8299
|
-
project: row.project ?? "",
|
|
8300
|
-
projectPath: row.projectPath ?? null,
|
|
8301
|
-
sourceFilePath: latestRaw?.sourcePath ?? null,
|
|
8302
|
-
createdAt: tsRange?.minTs ?? firstSeenAtMs,
|
|
8303
|
-
updatedAt: tsRange?.maxTs ?? firstSeenAtMs,
|
|
8304
|
-
deletedAt: visibility.deletedAt(row.id)
|
|
8305
|
-
};
|
|
8306
|
-
if (isDeleted) chat.isDeleted = true;
|
|
8307
|
-
chats2.push(chat);
|
|
8308
|
-
}
|
|
8309
|
-
return c.json({ chats: chats2 });
|
|
8310
|
-
});
|
|
8311
|
-
app2.delete("/api/chats/:id", (c) => {
|
|
8312
|
-
const id = c.req.param("id");
|
|
8313
|
-
const row = findArchiveChatBySourceId(id);
|
|
8314
|
-
if (!row) {
|
|
8315
|
-
return c.json({ error: "Chat not found" }, 404);
|
|
8316
|
-
}
|
|
8317
|
-
metadata2.softDelete(row.id);
|
|
8318
|
-
return c.body(null, 204);
|
|
8319
|
-
});
|
|
8320
|
-
app2.post("/api/chats/:id/restore", (c) => {
|
|
8321
|
-
const id = c.req.param("id");
|
|
8322
|
-
const row = findArchiveChatBySourceId(id);
|
|
8323
|
-
if (!row) {
|
|
8324
|
-
return c.json({ error: "Chat not found" }, 404);
|
|
8325
|
-
}
|
|
8326
|
-
metadata2.restore(row.id);
|
|
8327
|
-
return c.body(null, 204);
|
|
8328
|
-
});
|
|
8329
|
-
app2.patch("/api/chats/:id/title", async (c) => {
|
|
8330
|
-
const id = c.req.param("id");
|
|
8331
|
-
const row = findArchiveChatBySourceId(id);
|
|
8332
|
-
if (!row) {
|
|
8333
|
-
return c.json({ error: "Chat not found" }, 404);
|
|
8334
|
-
}
|
|
8335
|
-
let body;
|
|
8336
|
-
try {
|
|
8337
|
-
body = await c.req.json();
|
|
8338
|
-
} catch {
|
|
8339
|
-
return c.json({ error: "Invalid JSON body" }, 400);
|
|
8340
|
-
}
|
|
8341
|
-
if (!body || typeof body !== "object" || typeof body.title !== "string") {
|
|
8342
|
-
return c.json({ error: "Invalid title" }, 400);
|
|
8343
|
-
}
|
|
8344
|
-
const raw2 = body.title;
|
|
8345
|
-
if (raw2.length > 200) {
|
|
8346
|
-
return c.json({ error: "Title too long" }, 400);
|
|
8347
|
-
}
|
|
8348
|
-
const trimmed = raw2.trim();
|
|
8349
|
-
metadata2.setCustomTitle(row.id, trimmed.length > 0 ? trimmed : null);
|
|
8350
|
-
return c.body(null, 204);
|
|
8351
|
-
});
|
|
8352
|
-
app2.get("/api/chats/:id", (c) => {
|
|
8353
|
-
const id = c.req.param("id");
|
|
8354
|
-
const row = findArchiveChatBySourceId(id);
|
|
8355
|
-
if (!row) {
|
|
8356
|
-
return c.json({ error: "Chat not found" }, 404);
|
|
8357
|
-
}
|
|
8358
|
-
const visibility = loadChatVisibility(metadata2, {
|
|
8359
|
-
includeTrashed: c.req.query("includeTrashed") === "true"
|
|
8360
|
-
});
|
|
8361
|
-
if (!visibility.isVisible(row.id)) {
|
|
8362
|
-
return c.json({ error: "Chat not found" }, 404);
|
|
8363
|
-
}
|
|
8364
|
-
const rows = archive2.db.select().from(messages).where(
|
|
8365
|
-
and(
|
|
8366
|
-
eq(messages.agent, CLAUDE_CODE_AGENT),
|
|
8367
|
-
eq(messages.sourceId, id)
|
|
8368
|
-
)
|
|
8369
|
-
).orderBy(asc(messages.ts)).all();
|
|
8370
|
-
const messages2 = rows.map((m) => ({
|
|
8371
|
-
role: m.role,
|
|
8372
|
-
content: m.blocks.map(toApiBlock),
|
|
8373
|
-
timestamp: m.ts.toISOString()
|
|
8374
|
-
}));
|
|
8375
|
-
return c.json({ messages: messages2 });
|
|
8376
|
-
});
|
|
8377
|
-
function deriveTitle(archive3, metadata3, row) {
|
|
8378
|
-
const custom = metadata3.getCustomTitle(row.id);
|
|
8379
|
-
if (custom && custom.trim()) return custom;
|
|
8380
|
-
const firstUser = archive3.db.select({ text: messages.text }).from(messages).where(
|
|
8381
|
-
and(
|
|
8382
|
-
eq(messages.agent, CLAUDE_CODE_AGENT),
|
|
8383
|
-
eq(messages.sourceId, row.sourceId),
|
|
8384
|
-
eq(messages.role, "user")
|
|
8385
|
-
)
|
|
8386
|
-
).orderBy(asc(messages.ts)).limit(1).get();
|
|
8387
|
-
const text2 = firstUser?.text?.trim().split("\n")[0]?.trim();
|
|
8388
|
-
return text2 && text2.length > 0 ? text2 : "Untitled";
|
|
8389
|
-
}
|
|
8390
|
-
if (webDistDir2) {
|
|
8391
|
-
app2.use("*", serveStatic({ root: webDistDir2 }));
|
|
8392
|
-
app2.use("*", serveStatic({ root: webDistDir2, path: "index.html" }));
|
|
8393
|
-
}
|
|
8394
|
-
return app2;
|
|
8395
|
-
}
|
|
8396
|
-
|
|
8397
|
-
// src/archive/repository.ts
|
|
8398
|
-
import crypto5 from "crypto";
|
|
8399
|
-
import fs2 from "fs";
|
|
8400
|
-
import path from "path";
|
|
8401
|
-
import { fileURLToPath } from "url";
|
|
8402
|
-
import Database from "better-sqlite3";
|
|
8403
|
-
|
|
8404
|
-
// ../node_modules/.pnpm/drizzle-orm@0.45.2_@types+better-sqlite3@7.6.13_better-sqlite3@12.9.0/node_modules/drizzle-orm/better-sqlite3/driver.js
|
|
8405
|
-
import Client from "better-sqlite3";
|
|
8406
|
-
|
|
8407
8526
|
// ../node_modules/.pnpm/drizzle-orm@0.45.2_@types+better-sqlite3@7.6.13_better-sqlite3@12.9.0/node_modules/drizzle-orm/better-sqlite3/session.js
|
|
8408
8527
|
var BetterSQLiteSession = class extends SQLiteSession {
|
|
8409
8528
|
constructor(client, dialect, schema, options = {}) {
|
|
@@ -8563,7 +8682,7 @@ function drizzle(...params) {
|
|
|
8563
8682
|
})(drizzle || (drizzle = {}));
|
|
8564
8683
|
|
|
8565
8684
|
// ../node_modules/.pnpm/drizzle-orm@0.45.2_@types+better-sqlite3@7.6.13_better-sqlite3@12.9.0/node_modules/drizzle-orm/migrator.js
|
|
8566
|
-
import
|
|
8685
|
+
import crypto4 from "crypto";
|
|
8567
8686
|
import fs from "fs";
|
|
8568
8687
|
function readMigrationFiles(config) {
|
|
8569
8688
|
const migrationFolderTo = config.migrationsFolder;
|
|
@@ -8585,7 +8704,7 @@ function readMigrationFiles(config) {
|
|
|
8585
8704
|
sql: result,
|
|
8586
8705
|
bps: journalEntry.breakpoints,
|
|
8587
8706
|
folderMillis: journalEntry.when,
|
|
8588
|
-
hash:
|
|
8707
|
+
hash: crypto4.createHash("sha256").update(query).digest("hex")
|
|
8589
8708
|
});
|
|
8590
8709
|
} catch {
|
|
8591
8710
|
throw new Error(`No file ${migrationPath} found in ${migrationFolderTo} folder`);
|
|
@@ -8600,49 +8719,192 @@ function migrate(db, config) {
|
|
|
8600
8719
|
db.dialect.migrate(migrations, db.session, config);
|
|
8601
8720
|
}
|
|
8602
8721
|
|
|
8603
|
-
// src/
|
|
8604
|
-
|
|
8605
|
-
|
|
8606
|
-
var CHAT_ID_LENGTH = 6;
|
|
8607
|
-
var MAX_RETRIES = 5;
|
|
8608
|
-
function generateChatId({
|
|
8609
|
-
isTaken,
|
|
8610
|
-
randomIndex = () => crypto4.randomInt(CROCKFORD_ALPHABET.length)
|
|
8611
|
-
}) {
|
|
8612
|
-
for (let attempt = 0; attempt <= MAX_RETRIES; attempt++) {
|
|
8613
|
-
let code = "";
|
|
8614
|
-
for (let i = 0; i < CHAT_ID_LENGTH; i++) {
|
|
8615
|
-
code += CROCKFORD_ALPHABET[randomIndex()];
|
|
8616
|
-
}
|
|
8617
|
-
if (!isTaken(code)) {
|
|
8618
|
-
return code;
|
|
8619
|
-
}
|
|
8620
|
-
}
|
|
8621
|
-
throw new Error(
|
|
8622
|
-
`Failed to generate unique chat_id after ${MAX_RETRIES + 1} attempts`
|
|
8623
|
-
);
|
|
8624
|
-
}
|
|
8625
|
-
|
|
8626
|
-
// src/archive/repository.ts
|
|
8627
|
-
function resolveMigrationsFolder() {
|
|
8628
|
-
const here = path.dirname(fileURLToPath(import.meta.url));
|
|
8722
|
+
// src/storage/openStore.ts
|
|
8723
|
+
function resolveMigrationsFolder(callerUrl, migrationsSubdir) {
|
|
8724
|
+
const here = path.dirname(fileURLToPath(callerUrl));
|
|
8629
8725
|
const candidates = [
|
|
8630
|
-
path.join(here, "
|
|
8631
|
-
path.join(here, "
|
|
8726
|
+
path.join(here, "../..", migrationsSubdir),
|
|
8727
|
+
path.join(here, ".", migrationsSubdir)
|
|
8632
8728
|
];
|
|
8633
8729
|
const found = candidates.find((p) => fs2.existsSync(p));
|
|
8634
8730
|
if (!found) {
|
|
8635
|
-
throw new Error(
|
|
8731
|
+
throw new Error(`Could not locate migrations folder "${migrationsSubdir}"`);
|
|
8636
8732
|
}
|
|
8637
8733
|
return found;
|
|
8638
8734
|
}
|
|
8735
|
+
function openStore({
|
|
8736
|
+
dataDir: dataDir2,
|
|
8737
|
+
dbFile,
|
|
8738
|
+
callerUrl,
|
|
8739
|
+
migrationsSubdir,
|
|
8740
|
+
schema
|
|
8741
|
+
}) {
|
|
8742
|
+
const migrationsFolder = resolveMigrationsFolder(callerUrl, migrationsSubdir);
|
|
8743
|
+
fs2.mkdirSync(dataDir2, { recursive: true });
|
|
8744
|
+
const sqlite = new Database(path.join(dataDir2, dbFile));
|
|
8745
|
+
const db = drizzle(sqlite, { schema });
|
|
8746
|
+
migrate(db, { migrationsFolder });
|
|
8747
|
+
return { db, sqlite };
|
|
8748
|
+
}
|
|
8749
|
+
|
|
8750
|
+
// src/archive/schema.ts
|
|
8751
|
+
var schema_exports = {};
|
|
8752
|
+
__export(schema_exports, {
|
|
8753
|
+
archiveMeta: () => archiveMeta,
|
|
8754
|
+
chats: () => chats,
|
|
8755
|
+
ingestionEvents: () => ingestionEvents,
|
|
8756
|
+
messages: () => messages,
|
|
8757
|
+
rawMessages: () => rawMessages,
|
|
8758
|
+
schemaVersion: () => schemaVersion
|
|
8759
|
+
});
|
|
8760
|
+
var archiveMeta = sqliteTable("archive_meta", {
|
|
8761
|
+
id: integer("id").primaryKey(),
|
|
8762
|
+
archiveUuid: text("archive_uuid").notNull(),
|
|
8763
|
+
createdAt: integer("created_at", { mode: "timestamp_ms" }).notNull()
|
|
8764
|
+
});
|
|
8765
|
+
var schemaVersion = sqliteTable("schema_version", {
|
|
8766
|
+
version: integer("version").primaryKey(),
|
|
8767
|
+
appliedAt: integer("applied_at", { mode: "timestamp_ms" }).notNull()
|
|
8768
|
+
});
|
|
8769
|
+
var chats = sqliteTable(
|
|
8770
|
+
"chats",
|
|
8771
|
+
{
|
|
8772
|
+
id: text("id").primaryKey(),
|
|
8773
|
+
chatId: text("chat_id").notNull().unique(),
|
|
8774
|
+
agent: text("agent").notNull(),
|
|
8775
|
+
sourceId: text("source_id").notNull(),
|
|
8776
|
+
firstSeenAt: integer("first_seen_at", { mode: "timestamp_ms" }).notNull(),
|
|
8777
|
+
project: text("project"),
|
|
8778
|
+
projectPath: text("project_path")
|
|
8779
|
+
},
|
|
8780
|
+
(t) => [
|
|
8781
|
+
uniqueIndex("chats_agent_source_idx").on(t.agent, t.sourceId),
|
|
8782
|
+
// Backs the server-side Project filter (`WHERE coalesce(project,'') IN …`).
|
|
8783
|
+
index("chats_project_idx").on(t.project)
|
|
8784
|
+
]
|
|
8785
|
+
);
|
|
8786
|
+
var rawMessages = sqliteTable(
|
|
8787
|
+
"raw_messages",
|
|
8788
|
+
{
|
|
8789
|
+
id: integer("id").primaryKey({ autoIncrement: true }),
|
|
8790
|
+
agent: text("agent").notNull(),
|
|
8791
|
+
sourceId: text("source_id").notNull(),
|
|
8792
|
+
sourcePath: text("source_path").notNull(),
|
|
8793
|
+
sourceLocator: text("source_locator").notNull(),
|
|
8794
|
+
rawPayload: text("raw_payload").notNull(),
|
|
8795
|
+
payloadHash: text("payload_hash").notNull(),
|
|
8796
|
+
ingestedAt: integer("ingested_at", { mode: "timestamp_ms" }).notNull()
|
|
8797
|
+
},
|
|
8798
|
+
(t) => [
|
|
8799
|
+
uniqueIndex("raw_messages_idem_idx").on(t.agent, t.sourceId, t.payloadHash)
|
|
8800
|
+
]
|
|
8801
|
+
);
|
|
8802
|
+
var messages = sqliteTable(
|
|
8803
|
+
"messages",
|
|
8804
|
+
{
|
|
8805
|
+
id: integer("id").primaryKey({ autoIncrement: true }),
|
|
8806
|
+
agent: text("agent").notNull(),
|
|
8807
|
+
sourceId: text("source_id").notNull(),
|
|
8808
|
+
messageId: text("message_id").notNull(),
|
|
8809
|
+
role: text("role").notNull(),
|
|
8810
|
+
ts: integer("ts", { mode: "timestamp_ms" }).notNull(),
|
|
8811
|
+
text: text("text").notNull(),
|
|
8812
|
+
blocks: text("blocks", { mode: "json" }).notNull(),
|
|
8813
|
+
rawId: integer("raw_id").notNull().references(() => rawMessages.id)
|
|
8814
|
+
},
|
|
8815
|
+
(t) => [
|
|
8816
|
+
uniqueIndex("messages_canonical_idx").on(t.agent, t.sourceId, t.messageId)
|
|
8817
|
+
]
|
|
8818
|
+
);
|
|
8819
|
+
var ingestionEvents = sqliteTable("ingestion_events", {
|
|
8820
|
+
id: integer("id").primaryKey({ autoIncrement: true }),
|
|
8821
|
+
agent: text("agent").notNull(),
|
|
8822
|
+
sourceId: text("source_id").notNull(),
|
|
8823
|
+
sourcePath: text("source_path").notNull(),
|
|
8824
|
+
eventType: text("event_type").notNull(),
|
|
8825
|
+
detail: text("detail", { mode: "json" }).notNull(),
|
|
8826
|
+
observedAt: integer("observed_at", { mode: "timestamp_ms" }).notNull()
|
|
8827
|
+
});
|
|
8828
|
+
|
|
8829
|
+
// src/archive/read-seam.ts
|
|
8830
|
+
function createArchiveReadSeam(db) {
|
|
8831
|
+
return {
|
|
8832
|
+
listChatRows(opts) {
|
|
8833
|
+
const projects = opts?.projects;
|
|
8834
|
+
if (projects) {
|
|
8835
|
+
return db.select().from(chats).where(inArray(sql`coalesce(${chats.project}, '')`, projects)).all();
|
|
8836
|
+
}
|
|
8837
|
+
return db.select().from(chats).all();
|
|
8838
|
+
},
|
|
8839
|
+
findChatBySourceId(sourceId) {
|
|
8840
|
+
return db.select().from(chats).where(eq(chats.sourceId, sourceId)).get() ?? null;
|
|
8841
|
+
},
|
|
8842
|
+
findChatByChatId(chatId) {
|
|
8843
|
+
return db.select().from(chats).where(eq(chats.chatId, chatId)).get() ?? null;
|
|
8844
|
+
},
|
|
8845
|
+
listMessagesByChat(agent, sourceId) {
|
|
8846
|
+
return db.select().from(messages).where(and(eq(messages.agent, agent), eq(messages.sourceId, sourceId))).orderBy(asc(messages.ts)).all();
|
|
8847
|
+
},
|
|
8848
|
+
listChatTsRanges() {
|
|
8849
|
+
return db.select({
|
|
8850
|
+
agent: messages.agent,
|
|
8851
|
+
sourceId: messages.sourceId,
|
|
8852
|
+
minTs: sql`min(${messages.ts})`,
|
|
8853
|
+
maxTs: sql`max(${messages.ts})`
|
|
8854
|
+
}).from(messages).groupBy(messages.agent, messages.sourceId).all();
|
|
8855
|
+
},
|
|
8856
|
+
listLatestRawSourcePaths() {
|
|
8857
|
+
const ranked = db.select({
|
|
8858
|
+
agent: rawMessages.agent,
|
|
8859
|
+
sourceId: rawMessages.sourceId,
|
|
8860
|
+
sourcePath: rawMessages.sourcePath,
|
|
8861
|
+
rn: sql`row_number() over (partition by ${rawMessages.agent}, ${rawMessages.sourceId} order by ${rawMessages.ingestedAt} desc)`.as(
|
|
8862
|
+
"rn"
|
|
8863
|
+
)
|
|
8864
|
+
}).from(rawMessages).as("ranked_raw");
|
|
8865
|
+
return db.select({
|
|
8866
|
+
agent: ranked.agent,
|
|
8867
|
+
sourceId: ranked.sourceId,
|
|
8868
|
+
sourcePath: ranked.sourcePath
|
|
8869
|
+
}).from(ranked).where(eq(ranked.rn, 1)).all();
|
|
8870
|
+
},
|
|
8871
|
+
listFirstUserTexts() {
|
|
8872
|
+
const ranked = db.select({
|
|
8873
|
+
agent: messages.agent,
|
|
8874
|
+
sourceId: messages.sourceId,
|
|
8875
|
+
text: messages.text,
|
|
8876
|
+
rn: sql`row_number() over (partition by ${messages.agent}, ${messages.sourceId} order by ${messages.ts} asc)`.as(
|
|
8877
|
+
"rn"
|
|
8878
|
+
)
|
|
8879
|
+
}).from(messages).where(eq(messages.role, "user")).as("ranked_user");
|
|
8880
|
+
return db.select({
|
|
8881
|
+
agent: ranked.agent,
|
|
8882
|
+
sourceId: ranked.sourceId,
|
|
8883
|
+
text: ranked.text
|
|
8884
|
+
}).from(ranked).where(eq(ranked.rn, 1)).all();
|
|
8885
|
+
},
|
|
8886
|
+
listIngestionEvents() {
|
|
8887
|
+
return db.select().from(ingestionEvents).all();
|
|
8888
|
+
}
|
|
8889
|
+
};
|
|
8890
|
+
}
|
|
8891
|
+
|
|
8892
|
+
// src/archive/repository.ts
|
|
8893
|
+
function parseTs(ts) {
|
|
8894
|
+
const d = new Date(ts);
|
|
8895
|
+
if (Number.isNaN(d.getTime())) return /* @__PURE__ */ new Date(0);
|
|
8896
|
+
return d;
|
|
8897
|
+
}
|
|
8639
8898
|
function createArchiveRepository({
|
|
8640
8899
|
dataDir: dataDir2
|
|
8641
8900
|
}) {
|
|
8642
|
-
|
|
8643
|
-
|
|
8644
|
-
|
|
8645
|
-
|
|
8901
|
+
const { db, sqlite } = openStore({
|
|
8902
|
+
dataDir: dataDir2,
|
|
8903
|
+
dbFile: "archive.db",
|
|
8904
|
+
callerUrl: import.meta.url,
|
|
8905
|
+
migrationsSubdir: "drizzle/archive",
|
|
8906
|
+
schema: schema_exports
|
|
8907
|
+
});
|
|
8646
8908
|
const drizzleMigrations = sqlite.prepare("SELECT id, created_at FROM __drizzle_migrations ORDER BY id ASC").all();
|
|
8647
8909
|
for (const m of drizzleMigrations) {
|
|
8648
8910
|
db.insert(schemaVersion).values({ version: m.id, appliedAt: new Date(m.created_at) }).onConflictDoNothing().run();
|
|
@@ -8655,8 +8917,13 @@ function createArchiveRepository({
|
|
|
8655
8917
|
createdAt: /* @__PURE__ */ new Date()
|
|
8656
8918
|
}).run();
|
|
8657
8919
|
}
|
|
8920
|
+
function nextChatId() {
|
|
8921
|
+
return generateChatId({
|
|
8922
|
+
isTaken: (candidate) => db.select({ id: chats.id }).from(chats).where(eq(chats.chatId, candidate)).get() !== void 0
|
|
8923
|
+
});
|
|
8924
|
+
}
|
|
8658
8925
|
return {
|
|
8659
|
-
db,
|
|
8926
|
+
read: createArchiveReadSeam(db),
|
|
8660
8927
|
getArchiveUuid() {
|
|
8661
8928
|
const row = db.select().from(archiveMeta).get();
|
|
8662
8929
|
if (!row) {
|
|
@@ -8668,9 +8935,100 @@ function createArchiveRepository({
|
|
|
8668
8935
|
return db.select().from(schemaVersion).all().map((r) => ({ version: r.version, appliedAt: r.appliedAt }));
|
|
8669
8936
|
},
|
|
8670
8937
|
generateChatId() {
|
|
8671
|
-
return
|
|
8672
|
-
|
|
8673
|
-
|
|
8938
|
+
return nextChatId();
|
|
8939
|
+
},
|
|
8940
|
+
ensureChat(agent, sourceId, firstSeenAt, project, projectPath) {
|
|
8941
|
+
const existingChat = db.select().from(chats).where(and(eq(chats.agent, agent), eq(chats.sourceId, sourceId))).get();
|
|
8942
|
+
if (existingChat) {
|
|
8943
|
+
const updates = {};
|
|
8944
|
+
if (project && existingChat.project !== project) {
|
|
8945
|
+
updates.project = project;
|
|
8946
|
+
}
|
|
8947
|
+
if (projectPath && existingChat.projectPath !== projectPath) {
|
|
8948
|
+
updates.projectPath = projectPath;
|
|
8949
|
+
}
|
|
8950
|
+
if (Object.keys(updates).length > 0) {
|
|
8951
|
+
db.update(chats).set(updates).where(eq(chats.id, existingChat.id)).run();
|
|
8952
|
+
}
|
|
8953
|
+
return existingChat.id;
|
|
8954
|
+
}
|
|
8955
|
+
const id = crypto5.randomUUID();
|
|
8956
|
+
db.insert(chats).values({
|
|
8957
|
+
id,
|
|
8958
|
+
chatId: nextChatId(),
|
|
8959
|
+
agent,
|
|
8960
|
+
sourceId,
|
|
8961
|
+
firstSeenAt,
|
|
8962
|
+
project: project ?? null,
|
|
8963
|
+
projectPath: projectPath ?? null
|
|
8964
|
+
}).run();
|
|
8965
|
+
return id;
|
|
8966
|
+
},
|
|
8967
|
+
insertRawMessage(input) {
|
|
8968
|
+
const payloadJson = JSON.stringify(input.payload);
|
|
8969
|
+
const payloadHash = crypto5.createHash("sha256").update(payloadJson).digest("hex");
|
|
8970
|
+
const existing2 = db.select({ id: rawMessages.id }).from(rawMessages).where(
|
|
8971
|
+
and(
|
|
8972
|
+
eq(rawMessages.agent, input.agent),
|
|
8973
|
+
eq(rawMessages.sourceId, input.sourceId),
|
|
8974
|
+
eq(rawMessages.payloadHash, payloadHash)
|
|
8975
|
+
)
|
|
8976
|
+
).get();
|
|
8977
|
+
if (existing2) return { id: existing2.id, inserted: false };
|
|
8978
|
+
const inserted = db.insert(rawMessages).values({
|
|
8979
|
+
agent: input.agent,
|
|
8980
|
+
sourceId: input.sourceId,
|
|
8981
|
+
sourcePath: input.sourcePath,
|
|
8982
|
+
sourceLocator: input.sourceLocator,
|
|
8983
|
+
rawPayload: payloadJson,
|
|
8984
|
+
payloadHash,
|
|
8985
|
+
ingestedAt: input.ingestedAt
|
|
8986
|
+
}).returning({ id: rawMessages.id }).get();
|
|
8987
|
+
return { id: inserted.id, inserted: true };
|
|
8988
|
+
},
|
|
8989
|
+
upsertNormalizedMessage({ agent, sourceId, message, rawId }) {
|
|
8990
|
+
const existing2 = db.select().from(messages).where(
|
|
8991
|
+
and(
|
|
8992
|
+
eq(messages.agent, agent),
|
|
8993
|
+
eq(messages.sourceId, sourceId),
|
|
8994
|
+
eq(messages.messageId, message.messageId)
|
|
8995
|
+
)
|
|
8996
|
+
).get();
|
|
8997
|
+
const ts = parseTs(message.ts);
|
|
8998
|
+
if (!existing2) {
|
|
8999
|
+
db.insert(messages).values({
|
|
9000
|
+
agent,
|
|
9001
|
+
sourceId,
|
|
9002
|
+
messageId: message.messageId,
|
|
9003
|
+
role: message.role,
|
|
9004
|
+
ts,
|
|
9005
|
+
text: message.text,
|
|
9006
|
+
blocks: message.blocks,
|
|
9007
|
+
rawId
|
|
9008
|
+
}).run();
|
|
9009
|
+
return true;
|
|
9010
|
+
}
|
|
9011
|
+
if (ts.getTime() >= existing2.ts.getTime()) {
|
|
9012
|
+
db.update(messages).set({
|
|
9013
|
+
role: message.role,
|
|
9014
|
+
ts,
|
|
9015
|
+
text: message.text,
|
|
9016
|
+
blocks: message.blocks,
|
|
9017
|
+
rawId
|
|
9018
|
+
}).where(eq(messages.id, existing2.id)).run();
|
|
9019
|
+
return true;
|
|
9020
|
+
}
|
|
9021
|
+
return false;
|
|
9022
|
+
},
|
|
9023
|
+
recordIngestionEvent(event) {
|
|
9024
|
+
db.insert(ingestionEvents).values({
|
|
9025
|
+
agent: event.agent,
|
|
9026
|
+
sourceId: event.sourceId,
|
|
9027
|
+
sourcePath: event.sourcePath,
|
|
9028
|
+
eventType: event.eventType,
|
|
9029
|
+
detail: event.detail,
|
|
9030
|
+
observedAt: event.observedAt ?? /* @__PURE__ */ new Date()
|
|
9031
|
+
}).run();
|
|
8674
9032
|
},
|
|
8675
9033
|
close() {
|
|
8676
9034
|
sqlite.close();
|
|
@@ -8678,12 +9036,6 @@ function createArchiveRepository({
|
|
|
8678
9036
|
};
|
|
8679
9037
|
}
|
|
8680
9038
|
|
|
8681
|
-
// src/checkpoint/repository.ts
|
|
8682
|
-
import fs3 from "fs";
|
|
8683
|
-
import path2 from "path";
|
|
8684
|
-
import { fileURLToPath as fileURLToPath2 } from "url";
|
|
8685
|
-
import Database2 from "better-sqlite3";
|
|
8686
|
-
|
|
8687
9039
|
// src/checkpoint/schema.ts
|
|
8688
9040
|
var schema_exports2 = {};
|
|
8689
9041
|
__export(schema_exports2, {
|
|
@@ -8706,25 +9058,16 @@ var chatScanState = sqliteTable(
|
|
|
8706
9058
|
);
|
|
8707
9059
|
|
|
8708
9060
|
// src/checkpoint/repository.ts
|
|
8709
|
-
function resolveMigrationsFolder2() {
|
|
8710
|
-
const here = path2.dirname(fileURLToPath2(import.meta.url));
|
|
8711
|
-
const candidates = [
|
|
8712
|
-
path2.join(here, "../../drizzle/checkpoint"),
|
|
8713
|
-
path2.join(here, "./drizzle/checkpoint")
|
|
8714
|
-
];
|
|
8715
|
-
const found = candidates.find((p) => fs3.existsSync(p));
|
|
8716
|
-
if (!found) {
|
|
8717
|
-
throw new Error("Could not locate checkpoint drizzle migrations folder");
|
|
8718
|
-
}
|
|
8719
|
-
return found;
|
|
8720
|
-
}
|
|
8721
9061
|
function createCheckpointRepository({
|
|
8722
9062
|
dataDir: dataDir2
|
|
8723
9063
|
}) {
|
|
8724
|
-
|
|
8725
|
-
|
|
8726
|
-
|
|
8727
|
-
|
|
9064
|
+
const { db, sqlite } = openStore({
|
|
9065
|
+
dataDir: dataDir2,
|
|
9066
|
+
dbFile: "checkpoint.db",
|
|
9067
|
+
callerUrl: import.meta.url,
|
|
9068
|
+
migrationsSubdir: "drizzle/checkpoint",
|
|
9069
|
+
schema: schema_exports2
|
|
9070
|
+
});
|
|
8728
9071
|
return {
|
|
8729
9072
|
db,
|
|
8730
9073
|
getScanState(agent, sourceId) {
|
|
@@ -8772,12 +9115,16 @@ function createCheckpointRepository({
|
|
|
8772
9115
|
}
|
|
8773
9116
|
|
|
8774
9117
|
// src/metadata/repository.ts
|
|
8775
|
-
import
|
|
8776
|
-
import
|
|
8777
|
-
import { fileURLToPath as fileURLToPath3 } from "url";
|
|
8778
|
-
import Database3 from "better-sqlite3";
|
|
9118
|
+
import fs3 from "fs";
|
|
9119
|
+
import path2 from "path";
|
|
8779
9120
|
|
|
8780
9121
|
// src/metadata/schema.ts
|
|
9122
|
+
var schema_exports3 = {};
|
|
9123
|
+
__export(schema_exports3, {
|
|
9124
|
+
chatTags: () => chatTags,
|
|
9125
|
+
chatsMeta: () => chatsMeta,
|
|
9126
|
+
tags: () => tags
|
|
9127
|
+
});
|
|
8781
9128
|
var chatsMeta = sqliteTable("chats_meta", {
|
|
8782
9129
|
id: text("id").primaryKey(),
|
|
8783
9130
|
isDeleted: integer("is_deleted", { mode: "boolean" }).notNull().default(false),
|
|
@@ -8788,42 +9135,51 @@ var chatsMeta = sqliteTable("chats_meta", {
|
|
|
8788
9135
|
// view's independent "Deleted time" sort axis.
|
|
8789
9136
|
deletedAt: integer("deleted_at", { mode: "timestamp_ms" })
|
|
8790
9137
|
});
|
|
9138
|
+
var tags = sqliteTable("tags", {
|
|
9139
|
+
id: text("id").primaryKey(),
|
|
9140
|
+
name: text("name").notNull(),
|
|
9141
|
+
color: text("color").notNull(),
|
|
9142
|
+
createdAt: integer("created_at", { mode: "timestamp_ms" }).notNull(),
|
|
9143
|
+
updatedAt: integer("updated_at", { mode: "timestamp_ms" }).notNull()
|
|
9144
|
+
});
|
|
9145
|
+
var chatTags = sqliteTable(
|
|
9146
|
+
"chat_tags",
|
|
9147
|
+
{
|
|
9148
|
+
chatId: text("chat_id").notNull(),
|
|
9149
|
+
tagId: text("tag_id").notNull().references(() => tags.id, { onDelete: "cascade" })
|
|
9150
|
+
},
|
|
9151
|
+
(table) => [
|
|
9152
|
+
primaryKey({ columns: [table.chatId, table.tagId] }),
|
|
9153
|
+
index("chat_tags_tag_id_idx").on(table.tagId)
|
|
9154
|
+
]
|
|
9155
|
+
);
|
|
8791
9156
|
|
|
8792
9157
|
// src/metadata/repository.ts
|
|
8793
|
-
function resolveMigrationsFolder3() {
|
|
8794
|
-
const here = path3.dirname(fileURLToPath3(import.meta.url));
|
|
8795
|
-
const candidates = [
|
|
8796
|
-
path3.join(here, "../../drizzle"),
|
|
8797
|
-
path3.join(here, "./drizzle")
|
|
8798
|
-
];
|
|
8799
|
-
const found = candidates.find((p) => fs4.existsSync(p));
|
|
8800
|
-
if (!found) {
|
|
8801
|
-
throw new Error("Could not locate drizzle migrations folder");
|
|
8802
|
-
}
|
|
8803
|
-
return found;
|
|
8804
|
-
}
|
|
8805
9158
|
var DB_FILE = "metadata.db";
|
|
8806
9159
|
var LEGACY_DB_FILE = "data.db";
|
|
8807
9160
|
function migrateLegacyDbFile(dataDir2) {
|
|
8808
|
-
const legacy =
|
|
8809
|
-
const current =
|
|
8810
|
-
if (!
|
|
8811
|
-
if (
|
|
8812
|
-
|
|
9161
|
+
const legacy = path2.join(dataDir2, LEGACY_DB_FILE);
|
|
9162
|
+
const current = path2.join(dataDir2, DB_FILE);
|
|
9163
|
+
if (!fs3.existsSync(legacy)) return;
|
|
9164
|
+
if (fs3.existsSync(current)) return;
|
|
9165
|
+
fs3.renameSync(legacy, current);
|
|
8813
9166
|
}
|
|
8814
|
-
var
|
|
9167
|
+
var CLAUDE_CODE_AGENT = "claude-code";
|
|
8815
9168
|
function createMetadataRepository({
|
|
8816
9169
|
dataDir: dataDir2,
|
|
8817
9170
|
lookupInternalId,
|
|
8818
|
-
ensureChat
|
|
9171
|
+
ensureChat
|
|
8819
9172
|
}) {
|
|
8820
|
-
fs4.mkdirSync(dataDir2, { recursive: true });
|
|
8821
9173
|
migrateLegacyDbFile(dataDir2);
|
|
8822
|
-
const sqlite =
|
|
8823
|
-
|
|
8824
|
-
|
|
9174
|
+
const { db, sqlite } = openStore({
|
|
9175
|
+
dataDir: dataDir2,
|
|
9176
|
+
dbFile: DB_FILE,
|
|
9177
|
+
callerUrl: import.meta.url,
|
|
9178
|
+
migrationsSubdir: "drizzle",
|
|
9179
|
+
schema: schema_exports3
|
|
9180
|
+
});
|
|
8825
9181
|
if (lookupInternalId) {
|
|
8826
|
-
rekeyLegacyRows(sqlite, db, lookupInternalId,
|
|
9182
|
+
rekeyLegacyRows(sqlite, db, lookupInternalId, ensureChat);
|
|
8827
9183
|
}
|
|
8828
9184
|
return {
|
|
8829
9185
|
softDelete(internalId) {
|
|
@@ -8859,6 +9215,14 @@ function createMetadataRepository({
|
|
|
8859
9215
|
const row = db.select({ customTitle: chatsMeta.customTitle }).from(chatsMeta).where(eq(chatsMeta.id, internalId)).get();
|
|
8860
9216
|
return row?.customTitle ?? null;
|
|
8861
9217
|
},
|
|
9218
|
+
listCustomTitles() {
|
|
9219
|
+
const rows = db.select({ id: chatsMeta.id, customTitle: chatsMeta.customTitle }).from(chatsMeta).where(isNotNull(chatsMeta.customTitle)).all();
|
|
9220
|
+
const byId = /* @__PURE__ */ new Map();
|
|
9221
|
+
for (const row of rows) {
|
|
9222
|
+
if (row.customTitle !== null) byId.set(row.id, row.customTitle);
|
|
9223
|
+
}
|
|
9224
|
+
return byId;
|
|
9225
|
+
},
|
|
8862
9226
|
setCustomTitle(internalId, title) {
|
|
8863
9227
|
const now = /* @__PURE__ */ new Date();
|
|
8864
9228
|
db.insert(chatsMeta).values({
|
|
@@ -8874,15 +9238,15 @@ function createMetadataRepository({
|
|
|
8874
9238
|
};
|
|
8875
9239
|
}
|
|
8876
9240
|
var REKEY_USER_VERSION = 4;
|
|
8877
|
-
function rekeyLegacyRows(sqlite, db, lookupInternalId,
|
|
9241
|
+
function rekeyLegacyRows(sqlite, db, lookupInternalId, ensureChat) {
|
|
8878
9242
|
const current = sqlite.pragma("user_version", { simple: true });
|
|
8879
9243
|
if (current >= REKEY_USER_VERSION) return;
|
|
8880
9244
|
const rows = db.select({ id: chatsMeta.id }).from(chatsMeta).all();
|
|
8881
9245
|
for (const row of rows) {
|
|
8882
|
-
let target = lookupInternalId(
|
|
9246
|
+
let target = lookupInternalId(CLAUDE_CODE_AGENT, row.id);
|
|
8883
9247
|
if (target === null) {
|
|
8884
|
-
if (!
|
|
8885
|
-
target =
|
|
9248
|
+
if (!ensureChat) continue;
|
|
9249
|
+
target = ensureChat(CLAUDE_CODE_AGENT, row.id);
|
|
8886
9250
|
}
|
|
8887
9251
|
if (target === row.id) continue;
|
|
8888
9252
|
db.update(chatsMeta).set({ id: target, updatedAt: /* @__PURE__ */ new Date() }).where(eq(chatsMeta.id, row.id)).run();
|
|
@@ -8890,9 +9254,98 @@ function rekeyLegacyRows(sqlite, db, lookupInternalId, ensureChat2) {
|
|
|
8890
9254
|
sqlite.pragma(`user_version = ${REKEY_USER_VERSION}`);
|
|
8891
9255
|
}
|
|
8892
9256
|
|
|
9257
|
+
// src/metadata/tags.ts
|
|
9258
|
+
import { randomUUID } from "crypto";
|
|
9259
|
+
var DB_FILE2 = "metadata.db";
|
|
9260
|
+
function createTagRepository({
|
|
9261
|
+
dataDir: dataDir2
|
|
9262
|
+
}) {
|
|
9263
|
+
const { db } = openStore({
|
|
9264
|
+
dataDir: dataDir2,
|
|
9265
|
+
dbFile: DB_FILE2,
|
|
9266
|
+
callerUrl: import.meta.url,
|
|
9267
|
+
migrationsSubdir: "drizzle",
|
|
9268
|
+
schema: schema_exports3
|
|
9269
|
+
});
|
|
9270
|
+
function toTag(row) {
|
|
9271
|
+
return { id: row.id, name: row.name, color: row.color };
|
|
9272
|
+
}
|
|
9273
|
+
function assertColor(color) {
|
|
9274
|
+
if (!isColorToken(color)) {
|
|
9275
|
+
throw new Error(`Invalid tag color token: ${String(color)}`);
|
|
9276
|
+
}
|
|
9277
|
+
}
|
|
9278
|
+
return {
|
|
9279
|
+
createTag(name, color) {
|
|
9280
|
+
assertColor(color);
|
|
9281
|
+
const now = /* @__PURE__ */ new Date();
|
|
9282
|
+
const row = {
|
|
9283
|
+
id: randomUUID(),
|
|
9284
|
+
name,
|
|
9285
|
+
color,
|
|
9286
|
+
createdAt: now,
|
|
9287
|
+
updatedAt: now
|
|
9288
|
+
};
|
|
9289
|
+
db.insert(tags).values(row).run();
|
|
9290
|
+
return toTag(row);
|
|
9291
|
+
},
|
|
9292
|
+
listTags() {
|
|
9293
|
+
return db.select({ id: tags.id, name: tags.name, color: tags.color }).from(tags).all().map(toTag);
|
|
9294
|
+
},
|
|
9295
|
+
getTag(id) {
|
|
9296
|
+
const row = db.select({ id: tags.id, name: tags.name, color: tags.color }).from(tags).where(eq(tags.id, id)).get();
|
|
9297
|
+
return row ? toTag(row) : null;
|
|
9298
|
+
},
|
|
9299
|
+
renameTag(id, name) {
|
|
9300
|
+
db.update(tags).set({ name, updatedAt: /* @__PURE__ */ new Date() }).where(eq(tags.id, id)).run();
|
|
9301
|
+
},
|
|
9302
|
+
recolorTag(id, color) {
|
|
9303
|
+
assertColor(color);
|
|
9304
|
+
db.update(tags).set({ color, updatedAt: /* @__PURE__ */ new Date() }).where(eq(tags.id, id)).run();
|
|
9305
|
+
},
|
|
9306
|
+
deleteTag(id) {
|
|
9307
|
+
return db.transaction((tx) => {
|
|
9308
|
+
const removedFromChats = tx.select({ chatId: chatTags.chatId }).from(chatTags).where(eq(chatTags.tagId, id)).all().length;
|
|
9309
|
+
tx.delete(chatTags).where(eq(chatTags.tagId, id)).run();
|
|
9310
|
+
tx.delete(tags).where(eq(tags.id, id)).run();
|
|
9311
|
+
return { removedFromChats };
|
|
9312
|
+
});
|
|
9313
|
+
},
|
|
9314
|
+
assignTag(chatId, tagId) {
|
|
9315
|
+
db.insert(chatTags).values({ chatId, tagId }).onConflictDoNothing().run();
|
|
9316
|
+
},
|
|
9317
|
+
removeTag(chatId, tagId) {
|
|
9318
|
+
db.delete(chatTags).where(and(eq(chatTags.chatId, chatId), eq(chatTags.tagId, tagId))).run();
|
|
9319
|
+
},
|
|
9320
|
+
listTagsForChat(chatId) {
|
|
9321
|
+
return db.select({ id: tags.id, name: tags.name, color: tags.color }).from(chatTags).innerJoin(tags, eq(chatTags.tagId, tags.id)).where(eq(chatTags.chatId, chatId)).all().map(toTag);
|
|
9322
|
+
},
|
|
9323
|
+
listTagsByChat(chatIds) {
|
|
9324
|
+
const base = db.select({
|
|
9325
|
+
chatId: chatTags.chatId,
|
|
9326
|
+
id: tags.id,
|
|
9327
|
+
name: tags.name,
|
|
9328
|
+
color: tags.color
|
|
9329
|
+
}).from(chatTags).innerJoin(tags, eq(chatTags.tagId, tags.id));
|
|
9330
|
+
const rows = chatIds === void 0 ? base.all() : chatIds.length === 0 ? [] : base.where(inArray(chatTags.chatId, chatIds)).all();
|
|
9331
|
+
const byChat = /* @__PURE__ */ new Map();
|
|
9332
|
+
for (const row of rows) {
|
|
9333
|
+
const list = byChat.get(row.chatId) ?? [];
|
|
9334
|
+
list.push(toTag(row));
|
|
9335
|
+
byChat.set(row.chatId, list);
|
|
9336
|
+
}
|
|
9337
|
+
return byChat;
|
|
9338
|
+
},
|
|
9339
|
+
listChatIdsWithAllTags(tagIds) {
|
|
9340
|
+
const distinct = [...new Set(tagIds)];
|
|
9341
|
+
if (distinct.length === 0) return [];
|
|
9342
|
+
return db.select({ chatId: chatTags.chatId }).from(chatTags).where(inArray(chatTags.tagId, distinct)).groupBy(chatTags.chatId).having(sql`count(${chatTags.tagId}) = ${distinct.length}`).all().map((r) => r.chatId);
|
|
9343
|
+
}
|
|
9344
|
+
};
|
|
9345
|
+
}
|
|
9346
|
+
|
|
8893
9347
|
// src/ingestion/ingest.ts
|
|
8894
|
-
import
|
|
8895
|
-
import fs5 from "fs";
|
|
9348
|
+
import fs4 from "fs";
|
|
8896
9349
|
async function runIngestion(opts) {
|
|
8897
9350
|
const now = opts.now ?? (() => /* @__PURE__ */ new Date());
|
|
8898
9351
|
const result = {
|
|
@@ -8906,8 +9359,7 @@ async function runIngestion(opts) {
|
|
|
8906
9359
|
result.scanned += 1;
|
|
8907
9360
|
const stat4 = safeStat(ref.sourcePath);
|
|
8908
9361
|
const prior = opts.checkpoint.getScanState(plugin.id, ref.sourceId);
|
|
8909
|
-
ensureChat(
|
|
8910
|
-
opts.archive,
|
|
9362
|
+
opts.archive.ensureChat(
|
|
8911
9363
|
plugin.id,
|
|
8912
9364
|
ref.sourceId,
|
|
8913
9365
|
now(),
|
|
@@ -8919,40 +9371,23 @@ async function runIngestion(opts) {
|
|
|
8919
9371
|
continue;
|
|
8920
9372
|
}
|
|
8921
9373
|
for await (const raw2 of plugin.extractRaw(ref)) {
|
|
8922
|
-
const
|
|
8923
|
-
|
|
8924
|
-
|
|
8925
|
-
|
|
8926
|
-
|
|
8927
|
-
|
|
8928
|
-
|
|
8929
|
-
|
|
8930
|
-
).
|
|
8931
|
-
let rawId;
|
|
8932
|
-
if (existing) {
|
|
8933
|
-
rawId = existing.id;
|
|
8934
|
-
} else {
|
|
8935
|
-
const inserted = opts.archive.db.insert(rawMessages).values({
|
|
8936
|
-
agent: plugin.id,
|
|
8937
|
-
sourceId: ref.sourceId,
|
|
8938
|
-
sourcePath: raw2.sourcePath,
|
|
8939
|
-
sourceLocator: raw2.sourceLocator,
|
|
8940
|
-
rawPayload: payloadJson,
|
|
8941
|
-
payloadHash,
|
|
8942
|
-
ingestedAt: now()
|
|
8943
|
-
}).returning({ id: rawMessages.id }).get();
|
|
8944
|
-
rawId = inserted.id;
|
|
8945
|
-
result.rawInserted += 1;
|
|
8946
|
-
}
|
|
9374
|
+
const { id: rawId, inserted } = opts.archive.insertRawMessage({
|
|
9375
|
+
agent: plugin.id,
|
|
9376
|
+
sourceId: ref.sourceId,
|
|
9377
|
+
sourcePath: raw2.sourcePath,
|
|
9378
|
+
sourceLocator: raw2.sourceLocator,
|
|
9379
|
+
payload: raw2.payload,
|
|
9380
|
+
ingestedAt: now()
|
|
9381
|
+
});
|
|
9382
|
+
if (inserted) result.rawInserted += 1;
|
|
8947
9383
|
const normalized = plugin.normalize(raw2);
|
|
8948
9384
|
if (!normalized) continue;
|
|
8949
|
-
const upserted =
|
|
8950
|
-
|
|
8951
|
-
|
|
8952
|
-
|
|
8953
|
-
normalized,
|
|
9385
|
+
const upserted = opts.archive.upsertNormalizedMessage({
|
|
9386
|
+
agent: plugin.id,
|
|
9387
|
+
sourceId: ref.sourceId,
|
|
9388
|
+
message: normalized,
|
|
8954
9389
|
rawId
|
|
8955
|
-
);
|
|
9390
|
+
});
|
|
8956
9391
|
if (upserted) result.normalizedUpserted += 1;
|
|
8957
9392
|
}
|
|
8958
9393
|
if (stat4) {
|
|
@@ -8970,76 +9405,11 @@ async function runIngestion(opts) {
|
|
|
8970
9405
|
}
|
|
8971
9406
|
function safeStat(p) {
|
|
8972
9407
|
try {
|
|
8973
|
-
return
|
|
9408
|
+
return fs4.statSync(p);
|
|
8974
9409
|
} catch {
|
|
8975
9410
|
return null;
|
|
8976
9411
|
}
|
|
8977
9412
|
}
|
|
8978
|
-
function ensureChat(archive2, agent, sourceId, firstSeenAt, project, projectPath) {
|
|
8979
|
-
const existing = archive2.db.select().from(chats).where(and(eq(chats.agent, agent), eq(chats.sourceId, sourceId))).get();
|
|
8980
|
-
if (existing) {
|
|
8981
|
-
const updates = {};
|
|
8982
|
-
if (project && existing.project !== project) updates.project = project;
|
|
8983
|
-
if (projectPath && existing.projectPath !== projectPath) {
|
|
8984
|
-
updates.projectPath = projectPath;
|
|
8985
|
-
}
|
|
8986
|
-
if (Object.keys(updates).length > 0) {
|
|
8987
|
-
archive2.db.update(chats).set(updates).where(eq(chats.id, existing.id)).run();
|
|
8988
|
-
}
|
|
8989
|
-
return existing.id;
|
|
8990
|
-
}
|
|
8991
|
-
const id = crypto6.randomUUID();
|
|
8992
|
-
const chatId = archive2.generateChatId();
|
|
8993
|
-
archive2.db.insert(chats).values({
|
|
8994
|
-
id,
|
|
8995
|
-
chatId,
|
|
8996
|
-
agent,
|
|
8997
|
-
sourceId,
|
|
8998
|
-
firstSeenAt,
|
|
8999
|
-
project: project ?? null,
|
|
9000
|
-
projectPath: projectPath ?? null
|
|
9001
|
-
}).run();
|
|
9002
|
-
return id;
|
|
9003
|
-
}
|
|
9004
|
-
function upsertNormalized(archive2, agent, sourceId, msg, rawId) {
|
|
9005
|
-
const existing = archive2.db.select().from(messages).where(
|
|
9006
|
-
and(
|
|
9007
|
-
eq(messages.agent, agent),
|
|
9008
|
-
eq(messages.sourceId, sourceId),
|
|
9009
|
-
eq(messages.messageId, msg.messageId)
|
|
9010
|
-
)
|
|
9011
|
-
).get();
|
|
9012
|
-
const ts = parseTs(msg.ts);
|
|
9013
|
-
if (!existing) {
|
|
9014
|
-
archive2.db.insert(messages).values({
|
|
9015
|
-
agent,
|
|
9016
|
-
sourceId,
|
|
9017
|
-
messageId: msg.messageId,
|
|
9018
|
-
role: msg.role,
|
|
9019
|
-
ts,
|
|
9020
|
-
text: msg.text,
|
|
9021
|
-
blocks: msg.blocks,
|
|
9022
|
-
rawId
|
|
9023
|
-
}).run();
|
|
9024
|
-
return true;
|
|
9025
|
-
}
|
|
9026
|
-
if (ts.getTime() >= existing.ts.getTime()) {
|
|
9027
|
-
archive2.db.update(messages).set({
|
|
9028
|
-
role: msg.role,
|
|
9029
|
-
ts,
|
|
9030
|
-
text: msg.text,
|
|
9031
|
-
blocks: msg.blocks,
|
|
9032
|
-
rawId
|
|
9033
|
-
}).where(eq(messages.id, existing.id)).run();
|
|
9034
|
-
return true;
|
|
9035
|
-
}
|
|
9036
|
-
return false;
|
|
9037
|
-
}
|
|
9038
|
-
function parseTs(ts) {
|
|
9039
|
-
const d = new Date(ts);
|
|
9040
|
-
if (Number.isNaN(d.getTime())) return /* @__PURE__ */ new Date(0);
|
|
9041
|
-
return d;
|
|
9042
|
-
}
|
|
9043
9413
|
|
|
9044
9414
|
// src/ingestion/background.ts
|
|
9045
9415
|
function startIngestionInBackground(opts, bg = {}) {
|
|
@@ -9144,7 +9514,7 @@ var ReaddirpStream = class extends Readable3 {
|
|
|
9144
9514
|
this._directoryFilter = normalizeFilter(opts.directoryFilter);
|
|
9145
9515
|
const statMethod = opts.lstat ? lstat : stat;
|
|
9146
9516
|
if (wantBigintFsStats) {
|
|
9147
|
-
this._stat = (
|
|
9517
|
+
this._stat = (path5) => statMethod(path5, { bigint: true });
|
|
9148
9518
|
} else {
|
|
9149
9519
|
this._stat = statMethod;
|
|
9150
9520
|
}
|
|
@@ -9169,8 +9539,8 @@ var ReaddirpStream = class extends Readable3 {
|
|
|
9169
9539
|
const par = this.parent;
|
|
9170
9540
|
const fil = par && par.files;
|
|
9171
9541
|
if (fil && fil.length > 0) {
|
|
9172
|
-
const { path:
|
|
9173
|
-
const slice = fil.splice(0, batch).map((dirent) => this._formatEntry(dirent,
|
|
9542
|
+
const { path: path5, depth } = par;
|
|
9543
|
+
const slice = fil.splice(0, batch).map((dirent) => this._formatEntry(dirent, path5));
|
|
9174
9544
|
const awaited = await Promise.all(slice);
|
|
9175
9545
|
for (const entry of awaited) {
|
|
9176
9546
|
if (!entry)
|
|
@@ -9210,20 +9580,20 @@ var ReaddirpStream = class extends Readable3 {
|
|
|
9210
9580
|
this.reading = false;
|
|
9211
9581
|
}
|
|
9212
9582
|
}
|
|
9213
|
-
async _exploreDir(
|
|
9583
|
+
async _exploreDir(path5, depth) {
|
|
9214
9584
|
let files;
|
|
9215
9585
|
try {
|
|
9216
|
-
files = await readdir(
|
|
9586
|
+
files = await readdir(path5, this._rdOptions);
|
|
9217
9587
|
} catch (error) {
|
|
9218
9588
|
this._onError(error);
|
|
9219
9589
|
}
|
|
9220
|
-
return { files, depth, path:
|
|
9590
|
+
return { files, depth, path: path5 };
|
|
9221
9591
|
}
|
|
9222
|
-
async _formatEntry(dirent,
|
|
9592
|
+
async _formatEntry(dirent, path5) {
|
|
9223
9593
|
let entry;
|
|
9224
9594
|
const basename3 = this._isDirent ? dirent.name : dirent;
|
|
9225
9595
|
try {
|
|
9226
|
-
const fullPath = presolve(pjoin(
|
|
9596
|
+
const fullPath = presolve(pjoin(path5, basename3));
|
|
9227
9597
|
entry = { path: prelative(this._root, fullPath), fullPath, basename: basename3 };
|
|
9228
9598
|
entry[this._statsProp] = this._isDirent ? dirent : await this._stat(fullPath);
|
|
9229
9599
|
} catch (err) {
|
|
@@ -9623,16 +9993,16 @@ var delFromSet = (main, prop, item) => {
|
|
|
9623
9993
|
};
|
|
9624
9994
|
var isEmptySet = (val) => val instanceof Set ? val.size === 0 : !val;
|
|
9625
9995
|
var FsWatchInstances = /* @__PURE__ */ new Map();
|
|
9626
|
-
function createFsWatchInstance(
|
|
9996
|
+
function createFsWatchInstance(path5, options, listener, errHandler, emitRaw) {
|
|
9627
9997
|
const handleEvent = (rawEvent, evPath) => {
|
|
9628
|
-
listener(
|
|
9629
|
-
emitRaw(rawEvent, evPath, { watchedPath:
|
|
9630
|
-
if (evPath &&
|
|
9631
|
-
fsWatchBroadcast(sp.resolve(
|
|
9998
|
+
listener(path5);
|
|
9999
|
+
emitRaw(rawEvent, evPath, { watchedPath: path5 });
|
|
10000
|
+
if (evPath && path5 !== evPath) {
|
|
10001
|
+
fsWatchBroadcast(sp.resolve(path5, evPath), KEY_LISTENERS, sp.join(path5, evPath));
|
|
9632
10002
|
}
|
|
9633
10003
|
};
|
|
9634
10004
|
try {
|
|
9635
|
-
return fs_watch(
|
|
10005
|
+
return fs_watch(path5, {
|
|
9636
10006
|
persistent: options.persistent
|
|
9637
10007
|
}, handleEvent);
|
|
9638
10008
|
} catch (error) {
|
|
@@ -9648,12 +10018,12 @@ var fsWatchBroadcast = (fullPath, listenerType, val1, val2, val3) => {
|
|
|
9648
10018
|
listener(val1, val2, val3);
|
|
9649
10019
|
});
|
|
9650
10020
|
};
|
|
9651
|
-
var setFsWatchListener = (
|
|
10021
|
+
var setFsWatchListener = (path5, fullPath, options, handlers) => {
|
|
9652
10022
|
const { listener, errHandler, rawEmitter } = handlers;
|
|
9653
10023
|
let cont = FsWatchInstances.get(fullPath);
|
|
9654
10024
|
let watcher2;
|
|
9655
10025
|
if (!options.persistent) {
|
|
9656
|
-
watcher2 = createFsWatchInstance(
|
|
10026
|
+
watcher2 = createFsWatchInstance(path5, options, listener, errHandler, rawEmitter);
|
|
9657
10027
|
if (!watcher2)
|
|
9658
10028
|
return;
|
|
9659
10029
|
return watcher2.close.bind(watcher2);
|
|
@@ -9664,7 +10034,7 @@ var setFsWatchListener = (path6, fullPath, options, handlers) => {
|
|
|
9664
10034
|
addAndConvert(cont, KEY_RAW, rawEmitter);
|
|
9665
10035
|
} else {
|
|
9666
10036
|
watcher2 = createFsWatchInstance(
|
|
9667
|
-
|
|
10037
|
+
path5,
|
|
9668
10038
|
options,
|
|
9669
10039
|
fsWatchBroadcast.bind(null, fullPath, KEY_LISTENERS),
|
|
9670
10040
|
errHandler,
|
|
@@ -9679,7 +10049,7 @@ var setFsWatchListener = (path6, fullPath, options, handlers) => {
|
|
|
9679
10049
|
cont.watcherUnusable = true;
|
|
9680
10050
|
if (isWindows && error.code === "EPERM") {
|
|
9681
10051
|
try {
|
|
9682
|
-
const fd = await open(
|
|
10052
|
+
const fd = await open(path5, "r");
|
|
9683
10053
|
await fd.close();
|
|
9684
10054
|
broadcastErr(error);
|
|
9685
10055
|
} catch (err) {
|
|
@@ -9710,7 +10080,7 @@ var setFsWatchListener = (path6, fullPath, options, handlers) => {
|
|
|
9710
10080
|
};
|
|
9711
10081
|
};
|
|
9712
10082
|
var FsWatchFileInstances = /* @__PURE__ */ new Map();
|
|
9713
|
-
var setFsWatchFileListener = (
|
|
10083
|
+
var setFsWatchFileListener = (path5, fullPath, options, handlers) => {
|
|
9714
10084
|
const { listener, rawEmitter } = handlers;
|
|
9715
10085
|
let cont = FsWatchFileInstances.get(fullPath);
|
|
9716
10086
|
const copts = cont && cont.options;
|
|
@@ -9732,7 +10102,7 @@ var setFsWatchFileListener = (path6, fullPath, options, handlers) => {
|
|
|
9732
10102
|
});
|
|
9733
10103
|
const currmtime = curr.mtimeMs;
|
|
9734
10104
|
if (curr.size !== prev.size || currmtime > prev.mtimeMs || currmtime === 0) {
|
|
9735
|
-
foreach(cont.listeners, (listener2) => listener2(
|
|
10105
|
+
foreach(cont.listeners, (listener2) => listener2(path5, curr));
|
|
9736
10106
|
}
|
|
9737
10107
|
})
|
|
9738
10108
|
};
|
|
@@ -9762,13 +10132,13 @@ var NodeFsHandler = class {
|
|
|
9762
10132
|
* @param listener on fs change
|
|
9763
10133
|
* @returns closer for the watcher instance
|
|
9764
10134
|
*/
|
|
9765
|
-
_watchWithNodeFs(
|
|
10135
|
+
_watchWithNodeFs(path5, listener) {
|
|
9766
10136
|
const opts = this.fsw.options;
|
|
9767
|
-
const directory = sp.dirname(
|
|
9768
|
-
const basename3 = sp.basename(
|
|
10137
|
+
const directory = sp.dirname(path5);
|
|
10138
|
+
const basename3 = sp.basename(path5);
|
|
9769
10139
|
const parent = this.fsw._getWatchedDir(directory);
|
|
9770
10140
|
parent.add(basename3);
|
|
9771
|
-
const absolutePath = sp.resolve(
|
|
10141
|
+
const absolutePath = sp.resolve(path5);
|
|
9772
10142
|
const options = {
|
|
9773
10143
|
persistent: opts.persistent
|
|
9774
10144
|
};
|
|
@@ -9778,12 +10148,12 @@ var NodeFsHandler = class {
|
|
|
9778
10148
|
if (opts.usePolling) {
|
|
9779
10149
|
const enableBin = opts.interval !== opts.binaryInterval;
|
|
9780
10150
|
options.interval = enableBin && isBinaryPath(basename3) ? opts.binaryInterval : opts.interval;
|
|
9781
|
-
closer = setFsWatchFileListener(
|
|
10151
|
+
closer = setFsWatchFileListener(path5, absolutePath, options, {
|
|
9782
10152
|
listener,
|
|
9783
10153
|
rawEmitter: this.fsw._emitRaw
|
|
9784
10154
|
});
|
|
9785
10155
|
} else {
|
|
9786
|
-
closer = setFsWatchListener(
|
|
10156
|
+
closer = setFsWatchListener(path5, absolutePath, options, {
|
|
9787
10157
|
listener,
|
|
9788
10158
|
errHandler: this._boundHandleError,
|
|
9789
10159
|
rawEmitter: this.fsw._emitRaw
|
|
@@ -9805,7 +10175,7 @@ var NodeFsHandler = class {
|
|
|
9805
10175
|
let prevStats = stats;
|
|
9806
10176
|
if (parent.has(basename3))
|
|
9807
10177
|
return;
|
|
9808
|
-
const listener = async (
|
|
10178
|
+
const listener = async (path5, newStats) => {
|
|
9809
10179
|
if (!this.fsw._throttle(THROTTLE_MODE_WATCH, file, 5))
|
|
9810
10180
|
return;
|
|
9811
10181
|
if (!newStats || newStats.mtimeMs === 0) {
|
|
@@ -9819,11 +10189,11 @@ var NodeFsHandler = class {
|
|
|
9819
10189
|
this.fsw._emit(EV.CHANGE, file, newStats2);
|
|
9820
10190
|
}
|
|
9821
10191
|
if ((isMacos || isLinux || isFreeBSD) && prevStats.ino !== newStats2.ino) {
|
|
9822
|
-
this.fsw._closeFile(
|
|
10192
|
+
this.fsw._closeFile(path5);
|
|
9823
10193
|
prevStats = newStats2;
|
|
9824
10194
|
const closer2 = this._watchWithNodeFs(file, listener);
|
|
9825
10195
|
if (closer2)
|
|
9826
|
-
this.fsw._addPathCloser(
|
|
10196
|
+
this.fsw._addPathCloser(path5, closer2);
|
|
9827
10197
|
} else {
|
|
9828
10198
|
prevStats = newStats2;
|
|
9829
10199
|
}
|
|
@@ -9855,7 +10225,7 @@ var NodeFsHandler = class {
|
|
|
9855
10225
|
* @param item basename of this item
|
|
9856
10226
|
* @returns true if no more processing is needed for this entry.
|
|
9857
10227
|
*/
|
|
9858
|
-
async _handleSymlink(entry, directory,
|
|
10228
|
+
async _handleSymlink(entry, directory, path5, item) {
|
|
9859
10229
|
if (this.fsw.closed) {
|
|
9860
10230
|
return;
|
|
9861
10231
|
}
|
|
@@ -9865,7 +10235,7 @@ var NodeFsHandler = class {
|
|
|
9865
10235
|
this.fsw._incrReadyCount();
|
|
9866
10236
|
let linkPath;
|
|
9867
10237
|
try {
|
|
9868
|
-
linkPath = await fsrealpath(
|
|
10238
|
+
linkPath = await fsrealpath(path5);
|
|
9869
10239
|
} catch (e) {
|
|
9870
10240
|
this.fsw._emitReady();
|
|
9871
10241
|
return true;
|
|
@@ -9875,12 +10245,12 @@ var NodeFsHandler = class {
|
|
|
9875
10245
|
if (dir.has(item)) {
|
|
9876
10246
|
if (this.fsw._symlinkPaths.get(full) !== linkPath) {
|
|
9877
10247
|
this.fsw._symlinkPaths.set(full, linkPath);
|
|
9878
|
-
this.fsw._emit(EV.CHANGE,
|
|
10248
|
+
this.fsw._emit(EV.CHANGE, path5, entry.stats);
|
|
9879
10249
|
}
|
|
9880
10250
|
} else {
|
|
9881
10251
|
dir.add(item);
|
|
9882
10252
|
this.fsw._symlinkPaths.set(full, linkPath);
|
|
9883
|
-
this.fsw._emit(EV.ADD,
|
|
10253
|
+
this.fsw._emit(EV.ADD, path5, entry.stats);
|
|
9884
10254
|
}
|
|
9885
10255
|
this.fsw._emitReady();
|
|
9886
10256
|
return true;
|
|
@@ -9910,9 +10280,9 @@ var NodeFsHandler = class {
|
|
|
9910
10280
|
return;
|
|
9911
10281
|
}
|
|
9912
10282
|
const item = entry.path;
|
|
9913
|
-
let
|
|
10283
|
+
let path5 = sp.join(directory, item);
|
|
9914
10284
|
current.add(item);
|
|
9915
|
-
if (entry.stats.isSymbolicLink() && await this._handleSymlink(entry, directory,
|
|
10285
|
+
if (entry.stats.isSymbolicLink() && await this._handleSymlink(entry, directory, path5, item)) {
|
|
9916
10286
|
return;
|
|
9917
10287
|
}
|
|
9918
10288
|
if (this.fsw.closed) {
|
|
@@ -9921,8 +10291,8 @@ var NodeFsHandler = class {
|
|
|
9921
10291
|
}
|
|
9922
10292
|
if (item === target || !target && !previous.has(item)) {
|
|
9923
10293
|
this.fsw._incrReadyCount();
|
|
9924
|
-
|
|
9925
|
-
this._addToNodeFs(
|
|
10294
|
+
path5 = sp.join(dir, sp.relative(dir, path5));
|
|
10295
|
+
this._addToNodeFs(path5, initialAdd, wh, depth + 1);
|
|
9926
10296
|
}
|
|
9927
10297
|
}).on(EV.ERROR, this._boundHandleError);
|
|
9928
10298
|
return new Promise((resolve3, reject) => {
|
|
@@ -9991,13 +10361,13 @@ var NodeFsHandler = class {
|
|
|
9991
10361
|
* @param depth Child path actually targeted for watch
|
|
9992
10362
|
* @param target Child path actually targeted for watch
|
|
9993
10363
|
*/
|
|
9994
|
-
async _addToNodeFs(
|
|
10364
|
+
async _addToNodeFs(path5, initialAdd, priorWh, depth, target) {
|
|
9995
10365
|
const ready = this.fsw._emitReady;
|
|
9996
|
-
if (this.fsw._isIgnored(
|
|
10366
|
+
if (this.fsw._isIgnored(path5) || this.fsw.closed) {
|
|
9997
10367
|
ready();
|
|
9998
10368
|
return false;
|
|
9999
10369
|
}
|
|
10000
|
-
const wh = this.fsw._getWatchHelpers(
|
|
10370
|
+
const wh = this.fsw._getWatchHelpers(path5);
|
|
10001
10371
|
if (priorWh) {
|
|
10002
10372
|
wh.filterPath = (entry) => priorWh.filterPath(entry);
|
|
10003
10373
|
wh.filterDir = (entry) => priorWh.filterDir(entry);
|
|
@@ -10013,8 +10383,8 @@ var NodeFsHandler = class {
|
|
|
10013
10383
|
const follow = this.fsw.options.followSymlinks;
|
|
10014
10384
|
let closer;
|
|
10015
10385
|
if (stats.isDirectory()) {
|
|
10016
|
-
const absPath = sp.resolve(
|
|
10017
|
-
const targetPath = follow ? await fsrealpath(
|
|
10386
|
+
const absPath = sp.resolve(path5);
|
|
10387
|
+
const targetPath = follow ? await fsrealpath(path5) : path5;
|
|
10018
10388
|
if (this.fsw.closed)
|
|
10019
10389
|
return;
|
|
10020
10390
|
closer = await this._handleDir(wh.watchPath, stats, initialAdd, depth, target, wh, targetPath);
|
|
@@ -10024,29 +10394,29 @@ var NodeFsHandler = class {
|
|
|
10024
10394
|
this.fsw._symlinkPaths.set(absPath, targetPath);
|
|
10025
10395
|
}
|
|
10026
10396
|
} else if (stats.isSymbolicLink()) {
|
|
10027
|
-
const targetPath = follow ? await fsrealpath(
|
|
10397
|
+
const targetPath = follow ? await fsrealpath(path5) : path5;
|
|
10028
10398
|
if (this.fsw.closed)
|
|
10029
10399
|
return;
|
|
10030
10400
|
const parent = sp.dirname(wh.watchPath);
|
|
10031
10401
|
this.fsw._getWatchedDir(parent).add(wh.watchPath);
|
|
10032
10402
|
this.fsw._emit(EV.ADD, wh.watchPath, stats);
|
|
10033
|
-
closer = await this._handleDir(parent, stats, initialAdd, depth,
|
|
10403
|
+
closer = await this._handleDir(parent, stats, initialAdd, depth, path5, wh, targetPath);
|
|
10034
10404
|
if (this.fsw.closed)
|
|
10035
10405
|
return;
|
|
10036
10406
|
if (targetPath !== void 0) {
|
|
10037
|
-
this.fsw._symlinkPaths.set(sp.resolve(
|
|
10407
|
+
this.fsw._symlinkPaths.set(sp.resolve(path5), targetPath);
|
|
10038
10408
|
}
|
|
10039
10409
|
} else {
|
|
10040
10410
|
closer = this._handleFile(wh.watchPath, stats, initialAdd);
|
|
10041
10411
|
}
|
|
10042
10412
|
ready();
|
|
10043
10413
|
if (closer)
|
|
10044
|
-
this.fsw._addPathCloser(
|
|
10414
|
+
this.fsw._addPathCloser(path5, closer);
|
|
10045
10415
|
return false;
|
|
10046
10416
|
} catch (error) {
|
|
10047
10417
|
if (this.fsw._handleError(error)) {
|
|
10048
10418
|
ready();
|
|
10049
|
-
return
|
|
10419
|
+
return path5;
|
|
10050
10420
|
}
|
|
10051
10421
|
}
|
|
10052
10422
|
}
|
|
@@ -10089,24 +10459,24 @@ function createPattern(matcher) {
|
|
|
10089
10459
|
}
|
|
10090
10460
|
return () => false;
|
|
10091
10461
|
}
|
|
10092
|
-
function normalizePath(
|
|
10093
|
-
if (typeof
|
|
10462
|
+
function normalizePath(path5) {
|
|
10463
|
+
if (typeof path5 !== "string")
|
|
10094
10464
|
throw new Error("string expected");
|
|
10095
|
-
|
|
10096
|
-
|
|
10465
|
+
path5 = sp2.normalize(path5);
|
|
10466
|
+
path5 = path5.replace(/\\/g, "/");
|
|
10097
10467
|
let prepend = false;
|
|
10098
|
-
if (
|
|
10468
|
+
if (path5.startsWith("//"))
|
|
10099
10469
|
prepend = true;
|
|
10100
|
-
|
|
10470
|
+
path5 = path5.replace(DOUBLE_SLASH_RE, "/");
|
|
10101
10471
|
if (prepend)
|
|
10102
|
-
|
|
10103
|
-
return
|
|
10472
|
+
path5 = "/" + path5;
|
|
10473
|
+
return path5;
|
|
10104
10474
|
}
|
|
10105
10475
|
function matchPatterns(patterns, testString, stats) {
|
|
10106
|
-
const
|
|
10107
|
-
for (let
|
|
10108
|
-
const pattern = patterns[
|
|
10109
|
-
if (pattern(
|
|
10476
|
+
const path5 = normalizePath(testString);
|
|
10477
|
+
for (let index2 = 0; index2 < patterns.length; index2++) {
|
|
10478
|
+
const pattern = patterns[index2];
|
|
10479
|
+
if (pattern(path5, stats)) {
|
|
10110
10480
|
return true;
|
|
10111
10481
|
}
|
|
10112
10482
|
}
|
|
@@ -10144,19 +10514,19 @@ var toUnix = (string) => {
|
|
|
10144
10514
|
}
|
|
10145
10515
|
return str;
|
|
10146
10516
|
};
|
|
10147
|
-
var normalizePathToUnix = (
|
|
10148
|
-
var normalizeIgnored = (cwd = "") => (
|
|
10149
|
-
if (typeof
|
|
10150
|
-
return normalizePathToUnix(sp2.isAbsolute(
|
|
10517
|
+
var normalizePathToUnix = (path5) => toUnix(sp2.normalize(toUnix(path5)));
|
|
10518
|
+
var normalizeIgnored = (cwd = "") => (path5) => {
|
|
10519
|
+
if (typeof path5 === "string") {
|
|
10520
|
+
return normalizePathToUnix(sp2.isAbsolute(path5) ? path5 : sp2.join(cwd, path5));
|
|
10151
10521
|
} else {
|
|
10152
|
-
return
|
|
10522
|
+
return path5;
|
|
10153
10523
|
}
|
|
10154
10524
|
};
|
|
10155
|
-
var getAbsolutePath = (
|
|
10156
|
-
if (sp2.isAbsolute(
|
|
10157
|
-
return
|
|
10525
|
+
var getAbsolutePath = (path5, cwd) => {
|
|
10526
|
+
if (sp2.isAbsolute(path5)) {
|
|
10527
|
+
return path5;
|
|
10158
10528
|
}
|
|
10159
|
-
return sp2.join(cwd,
|
|
10529
|
+
return sp2.join(cwd, path5);
|
|
10160
10530
|
};
|
|
10161
10531
|
var EMPTY_SET = Object.freeze(/* @__PURE__ */ new Set());
|
|
10162
10532
|
var DirEntry = class {
|
|
@@ -10221,10 +10591,10 @@ var WatchHelper = class {
|
|
|
10221
10591
|
dirParts;
|
|
10222
10592
|
followSymlinks;
|
|
10223
10593
|
statMethod;
|
|
10224
|
-
constructor(
|
|
10594
|
+
constructor(path5, follow, fsw) {
|
|
10225
10595
|
this.fsw = fsw;
|
|
10226
|
-
const watchPath =
|
|
10227
|
-
this.path =
|
|
10596
|
+
const watchPath = path5;
|
|
10597
|
+
this.path = path5 = path5.replace(REPLACER_RE, "");
|
|
10228
10598
|
this.watchPath = watchPath;
|
|
10229
10599
|
this.fullWatchPath = sp2.resolve(watchPath);
|
|
10230
10600
|
this.dirParts = [];
|
|
@@ -10364,20 +10734,20 @@ var FSWatcher = class extends EventEmitter {
|
|
|
10364
10734
|
this._closePromise = void 0;
|
|
10365
10735
|
let paths = unifyPaths(paths_);
|
|
10366
10736
|
if (cwd) {
|
|
10367
|
-
paths = paths.map((
|
|
10368
|
-
const absPath = getAbsolutePath(
|
|
10737
|
+
paths = paths.map((path5) => {
|
|
10738
|
+
const absPath = getAbsolutePath(path5, cwd);
|
|
10369
10739
|
return absPath;
|
|
10370
10740
|
});
|
|
10371
10741
|
}
|
|
10372
|
-
paths.forEach((
|
|
10373
|
-
this._removeIgnoredPath(
|
|
10742
|
+
paths.forEach((path5) => {
|
|
10743
|
+
this._removeIgnoredPath(path5);
|
|
10374
10744
|
});
|
|
10375
10745
|
this._userIgnored = void 0;
|
|
10376
10746
|
if (!this._readyCount)
|
|
10377
10747
|
this._readyCount = 0;
|
|
10378
10748
|
this._readyCount += paths.length;
|
|
10379
|
-
Promise.all(paths.map(async (
|
|
10380
|
-
const res = await this._nodeFsHandler._addToNodeFs(
|
|
10749
|
+
Promise.all(paths.map(async (path5) => {
|
|
10750
|
+
const res = await this._nodeFsHandler._addToNodeFs(path5, !_internal, void 0, 0, _origAdd);
|
|
10381
10751
|
if (res)
|
|
10382
10752
|
this._emitReady();
|
|
10383
10753
|
return res;
|
|
@@ -10399,17 +10769,17 @@ var FSWatcher = class extends EventEmitter {
|
|
|
10399
10769
|
return this;
|
|
10400
10770
|
const paths = unifyPaths(paths_);
|
|
10401
10771
|
const { cwd } = this.options;
|
|
10402
|
-
paths.forEach((
|
|
10403
|
-
if (!sp2.isAbsolute(
|
|
10772
|
+
paths.forEach((path5) => {
|
|
10773
|
+
if (!sp2.isAbsolute(path5) && !this._closers.has(path5)) {
|
|
10404
10774
|
if (cwd)
|
|
10405
|
-
|
|
10406
|
-
|
|
10775
|
+
path5 = sp2.join(cwd, path5);
|
|
10776
|
+
path5 = sp2.resolve(path5);
|
|
10407
10777
|
}
|
|
10408
|
-
this._closePath(
|
|
10409
|
-
this._addIgnoredPath(
|
|
10410
|
-
if (this._watched.has(
|
|
10778
|
+
this._closePath(path5);
|
|
10779
|
+
this._addIgnoredPath(path5);
|
|
10780
|
+
if (this._watched.has(path5)) {
|
|
10411
10781
|
this._addIgnoredPath({
|
|
10412
|
-
path:
|
|
10782
|
+
path: path5,
|
|
10413
10783
|
recursive: true
|
|
10414
10784
|
});
|
|
10415
10785
|
}
|
|
@@ -10453,8 +10823,8 @@ var FSWatcher = class extends EventEmitter {
|
|
|
10453
10823
|
const watchList = {};
|
|
10454
10824
|
this._watched.forEach((entry, dir) => {
|
|
10455
10825
|
const key = this.options.cwd ? sp2.relative(this.options.cwd, dir) : dir;
|
|
10456
|
-
const
|
|
10457
|
-
watchList[
|
|
10826
|
+
const index2 = key || ONE_DOT;
|
|
10827
|
+
watchList[index2] = entry.getChildren().sort();
|
|
10458
10828
|
});
|
|
10459
10829
|
return watchList;
|
|
10460
10830
|
}
|
|
@@ -10473,38 +10843,38 @@ var FSWatcher = class extends EventEmitter {
|
|
|
10473
10843
|
* @param stats arguments to be passed with event
|
|
10474
10844
|
* @returns the error if defined, otherwise the value of the FSWatcher instance's `closed` flag
|
|
10475
10845
|
*/
|
|
10476
|
-
async _emit(event,
|
|
10846
|
+
async _emit(event, path5, stats) {
|
|
10477
10847
|
if (this.closed)
|
|
10478
10848
|
return;
|
|
10479
10849
|
const opts = this.options;
|
|
10480
10850
|
if (isWindows)
|
|
10481
|
-
|
|
10851
|
+
path5 = sp2.normalize(path5);
|
|
10482
10852
|
if (opts.cwd)
|
|
10483
|
-
|
|
10484
|
-
const args = [
|
|
10853
|
+
path5 = sp2.relative(opts.cwd, path5);
|
|
10854
|
+
const args = [path5];
|
|
10485
10855
|
if (stats != null)
|
|
10486
10856
|
args.push(stats);
|
|
10487
10857
|
const awf = opts.awaitWriteFinish;
|
|
10488
10858
|
let pw;
|
|
10489
|
-
if (awf && (pw = this._pendingWrites.get(
|
|
10859
|
+
if (awf && (pw = this._pendingWrites.get(path5))) {
|
|
10490
10860
|
pw.lastChange = /* @__PURE__ */ new Date();
|
|
10491
10861
|
return this;
|
|
10492
10862
|
}
|
|
10493
10863
|
if (opts.atomic) {
|
|
10494
10864
|
if (event === EVENTS.UNLINK) {
|
|
10495
|
-
this._pendingUnlinks.set(
|
|
10865
|
+
this._pendingUnlinks.set(path5, [event, ...args]);
|
|
10496
10866
|
setTimeout(() => {
|
|
10497
|
-
this._pendingUnlinks.forEach((entry,
|
|
10867
|
+
this._pendingUnlinks.forEach((entry, path6) => {
|
|
10498
10868
|
this.emit(...entry);
|
|
10499
10869
|
this.emit(EVENTS.ALL, ...entry);
|
|
10500
|
-
this._pendingUnlinks.delete(
|
|
10870
|
+
this._pendingUnlinks.delete(path6);
|
|
10501
10871
|
});
|
|
10502
10872
|
}, typeof opts.atomic === "number" ? opts.atomic : 100);
|
|
10503
10873
|
return this;
|
|
10504
10874
|
}
|
|
10505
|
-
if (event === EVENTS.ADD && this._pendingUnlinks.has(
|
|
10875
|
+
if (event === EVENTS.ADD && this._pendingUnlinks.has(path5)) {
|
|
10506
10876
|
event = EVENTS.CHANGE;
|
|
10507
|
-
this._pendingUnlinks.delete(
|
|
10877
|
+
this._pendingUnlinks.delete(path5);
|
|
10508
10878
|
}
|
|
10509
10879
|
}
|
|
10510
10880
|
if (awf && (event === EVENTS.ADD || event === EVENTS.CHANGE) && this._readyEmitted) {
|
|
@@ -10522,16 +10892,16 @@ var FSWatcher = class extends EventEmitter {
|
|
|
10522
10892
|
this.emitWithAll(event, args);
|
|
10523
10893
|
}
|
|
10524
10894
|
};
|
|
10525
|
-
this._awaitWriteFinish(
|
|
10895
|
+
this._awaitWriteFinish(path5, awf.stabilityThreshold, event, awfEmit);
|
|
10526
10896
|
return this;
|
|
10527
10897
|
}
|
|
10528
10898
|
if (event === EVENTS.CHANGE) {
|
|
10529
|
-
const isThrottled = !this._throttle(EVENTS.CHANGE,
|
|
10899
|
+
const isThrottled = !this._throttle(EVENTS.CHANGE, path5, 50);
|
|
10530
10900
|
if (isThrottled)
|
|
10531
10901
|
return this;
|
|
10532
10902
|
}
|
|
10533
10903
|
if (opts.alwaysStat && stats === void 0 && (event === EVENTS.ADD || event === EVENTS.ADD_DIR || event === EVENTS.CHANGE)) {
|
|
10534
|
-
const fullPath = opts.cwd ? sp2.join(opts.cwd,
|
|
10904
|
+
const fullPath = opts.cwd ? sp2.join(opts.cwd, path5) : path5;
|
|
10535
10905
|
let stats2;
|
|
10536
10906
|
try {
|
|
10537
10907
|
stats2 = await stat3(fullPath);
|
|
@@ -10562,23 +10932,23 @@ var FSWatcher = class extends EventEmitter {
|
|
|
10562
10932
|
* @param timeout duration of time to suppress duplicate actions
|
|
10563
10933
|
* @returns tracking object or false if action should be suppressed
|
|
10564
10934
|
*/
|
|
10565
|
-
_throttle(actionType,
|
|
10935
|
+
_throttle(actionType, path5, timeout) {
|
|
10566
10936
|
if (!this._throttled.has(actionType)) {
|
|
10567
10937
|
this._throttled.set(actionType, /* @__PURE__ */ new Map());
|
|
10568
10938
|
}
|
|
10569
10939
|
const action2 = this._throttled.get(actionType);
|
|
10570
10940
|
if (!action2)
|
|
10571
10941
|
throw new Error("invalid throttle");
|
|
10572
|
-
const actionPath = action2.get(
|
|
10942
|
+
const actionPath = action2.get(path5);
|
|
10573
10943
|
if (actionPath) {
|
|
10574
10944
|
actionPath.count++;
|
|
10575
10945
|
return false;
|
|
10576
10946
|
}
|
|
10577
10947
|
let timeoutObject;
|
|
10578
10948
|
const clear = () => {
|
|
10579
|
-
const item = action2.get(
|
|
10949
|
+
const item = action2.get(path5);
|
|
10580
10950
|
const count = item ? item.count : 0;
|
|
10581
|
-
action2.delete(
|
|
10951
|
+
action2.delete(path5);
|
|
10582
10952
|
clearTimeout(timeoutObject);
|
|
10583
10953
|
if (item)
|
|
10584
10954
|
clearTimeout(item.timeoutObject);
|
|
@@ -10586,7 +10956,7 @@ var FSWatcher = class extends EventEmitter {
|
|
|
10586
10956
|
};
|
|
10587
10957
|
timeoutObject = setTimeout(clear, timeout);
|
|
10588
10958
|
const thr = { timeoutObject, clear, count: 0 };
|
|
10589
|
-
action2.set(
|
|
10959
|
+
action2.set(path5, thr);
|
|
10590
10960
|
return thr;
|
|
10591
10961
|
}
|
|
10592
10962
|
_incrReadyCount() {
|
|
@@ -10600,44 +10970,44 @@ var FSWatcher = class extends EventEmitter {
|
|
|
10600
10970
|
* @param event
|
|
10601
10971
|
* @param awfEmit Callback to be called when ready for event to be emitted.
|
|
10602
10972
|
*/
|
|
10603
|
-
_awaitWriteFinish(
|
|
10973
|
+
_awaitWriteFinish(path5, threshold, event, awfEmit) {
|
|
10604
10974
|
const awf = this.options.awaitWriteFinish;
|
|
10605
10975
|
if (typeof awf !== "object")
|
|
10606
10976
|
return;
|
|
10607
10977
|
const pollInterval = awf.pollInterval;
|
|
10608
10978
|
let timeoutHandler;
|
|
10609
|
-
let fullPath =
|
|
10610
|
-
if (this.options.cwd && !sp2.isAbsolute(
|
|
10611
|
-
fullPath = sp2.join(this.options.cwd,
|
|
10979
|
+
let fullPath = path5;
|
|
10980
|
+
if (this.options.cwd && !sp2.isAbsolute(path5)) {
|
|
10981
|
+
fullPath = sp2.join(this.options.cwd, path5);
|
|
10612
10982
|
}
|
|
10613
10983
|
const now = /* @__PURE__ */ new Date();
|
|
10614
10984
|
const writes = this._pendingWrites;
|
|
10615
10985
|
function awaitWriteFinishFn(prevStat) {
|
|
10616
10986
|
statcb(fullPath, (err, curStat) => {
|
|
10617
|
-
if (err || !writes.has(
|
|
10987
|
+
if (err || !writes.has(path5)) {
|
|
10618
10988
|
if (err && err.code !== "ENOENT")
|
|
10619
10989
|
awfEmit(err);
|
|
10620
10990
|
return;
|
|
10621
10991
|
}
|
|
10622
10992
|
const now2 = Number(/* @__PURE__ */ new Date());
|
|
10623
10993
|
if (prevStat && curStat.size !== prevStat.size) {
|
|
10624
|
-
writes.get(
|
|
10994
|
+
writes.get(path5).lastChange = now2;
|
|
10625
10995
|
}
|
|
10626
|
-
const pw = writes.get(
|
|
10996
|
+
const pw = writes.get(path5);
|
|
10627
10997
|
const df = now2 - pw.lastChange;
|
|
10628
10998
|
if (df >= threshold) {
|
|
10629
|
-
writes.delete(
|
|
10999
|
+
writes.delete(path5);
|
|
10630
11000
|
awfEmit(void 0, curStat);
|
|
10631
11001
|
} else {
|
|
10632
11002
|
timeoutHandler = setTimeout(awaitWriteFinishFn, pollInterval, curStat);
|
|
10633
11003
|
}
|
|
10634
11004
|
});
|
|
10635
11005
|
}
|
|
10636
|
-
if (!writes.has(
|
|
10637
|
-
writes.set(
|
|
11006
|
+
if (!writes.has(path5)) {
|
|
11007
|
+
writes.set(path5, {
|
|
10638
11008
|
lastChange: now,
|
|
10639
11009
|
cancelWait: () => {
|
|
10640
|
-
writes.delete(
|
|
11010
|
+
writes.delete(path5);
|
|
10641
11011
|
clearTimeout(timeoutHandler);
|
|
10642
11012
|
return event;
|
|
10643
11013
|
}
|
|
@@ -10648,8 +11018,8 @@ var FSWatcher = class extends EventEmitter {
|
|
|
10648
11018
|
/**
|
|
10649
11019
|
* Determines whether user has asked to ignore this path.
|
|
10650
11020
|
*/
|
|
10651
|
-
_isIgnored(
|
|
10652
|
-
if (this.options.atomic && DOT_RE.test(
|
|
11021
|
+
_isIgnored(path5, stats) {
|
|
11022
|
+
if (this.options.atomic && DOT_RE.test(path5))
|
|
10653
11023
|
return true;
|
|
10654
11024
|
if (!this._userIgnored) {
|
|
10655
11025
|
const { cwd } = this.options;
|
|
@@ -10659,17 +11029,17 @@ var FSWatcher = class extends EventEmitter {
|
|
|
10659
11029
|
const list = [...ignoredPaths.map(normalizeIgnored(cwd)), ...ignored];
|
|
10660
11030
|
this._userIgnored = anymatch(list, void 0);
|
|
10661
11031
|
}
|
|
10662
|
-
return this._userIgnored(
|
|
11032
|
+
return this._userIgnored(path5, stats);
|
|
10663
11033
|
}
|
|
10664
|
-
_isntIgnored(
|
|
10665
|
-
return !this._isIgnored(
|
|
11034
|
+
_isntIgnored(path5, stat4) {
|
|
11035
|
+
return !this._isIgnored(path5, stat4);
|
|
10666
11036
|
}
|
|
10667
11037
|
/**
|
|
10668
11038
|
* Provides a set of common helpers and properties relating to symlink handling.
|
|
10669
11039
|
* @param path file or directory pattern being watched
|
|
10670
11040
|
*/
|
|
10671
|
-
_getWatchHelpers(
|
|
10672
|
-
return new WatchHelper(
|
|
11041
|
+
_getWatchHelpers(path5) {
|
|
11042
|
+
return new WatchHelper(path5, this.options.followSymlinks, this);
|
|
10673
11043
|
}
|
|
10674
11044
|
// Directory helpers
|
|
10675
11045
|
// -----------------
|
|
@@ -10701,63 +11071,63 @@ var FSWatcher = class extends EventEmitter {
|
|
|
10701
11071
|
* @param item base path of item/directory
|
|
10702
11072
|
*/
|
|
10703
11073
|
_remove(directory, item, isDirectory) {
|
|
10704
|
-
const
|
|
10705
|
-
const fullPath = sp2.resolve(
|
|
10706
|
-
isDirectory = isDirectory != null ? isDirectory : this._watched.has(
|
|
10707
|
-
if (!this._throttle("remove",
|
|
11074
|
+
const path5 = sp2.join(directory, item);
|
|
11075
|
+
const fullPath = sp2.resolve(path5);
|
|
11076
|
+
isDirectory = isDirectory != null ? isDirectory : this._watched.has(path5) || this._watched.has(fullPath);
|
|
11077
|
+
if (!this._throttle("remove", path5, 100))
|
|
10708
11078
|
return;
|
|
10709
11079
|
if (!isDirectory && this._watched.size === 1) {
|
|
10710
11080
|
this.add(directory, item, true);
|
|
10711
11081
|
}
|
|
10712
|
-
const wp = this._getWatchedDir(
|
|
11082
|
+
const wp = this._getWatchedDir(path5);
|
|
10713
11083
|
const nestedDirectoryChildren = wp.getChildren();
|
|
10714
|
-
nestedDirectoryChildren.forEach((nested) => this._remove(
|
|
11084
|
+
nestedDirectoryChildren.forEach((nested) => this._remove(path5, nested));
|
|
10715
11085
|
const parent = this._getWatchedDir(directory);
|
|
10716
11086
|
const wasTracked = parent.has(item);
|
|
10717
11087
|
parent.remove(item);
|
|
10718
11088
|
if (this._symlinkPaths.has(fullPath)) {
|
|
10719
11089
|
this._symlinkPaths.delete(fullPath);
|
|
10720
11090
|
}
|
|
10721
|
-
let relPath =
|
|
11091
|
+
let relPath = path5;
|
|
10722
11092
|
if (this.options.cwd)
|
|
10723
|
-
relPath = sp2.relative(this.options.cwd,
|
|
11093
|
+
relPath = sp2.relative(this.options.cwd, path5);
|
|
10724
11094
|
if (this.options.awaitWriteFinish && this._pendingWrites.has(relPath)) {
|
|
10725
11095
|
const event = this._pendingWrites.get(relPath).cancelWait();
|
|
10726
11096
|
if (event === EVENTS.ADD)
|
|
10727
11097
|
return;
|
|
10728
11098
|
}
|
|
10729
|
-
this._watched.delete(
|
|
11099
|
+
this._watched.delete(path5);
|
|
10730
11100
|
this._watched.delete(fullPath);
|
|
10731
11101
|
const eventName = isDirectory ? EVENTS.UNLINK_DIR : EVENTS.UNLINK;
|
|
10732
|
-
if (wasTracked && !this._isIgnored(
|
|
10733
|
-
this._emit(eventName,
|
|
10734
|
-
this._closePath(
|
|
11102
|
+
if (wasTracked && !this._isIgnored(path5))
|
|
11103
|
+
this._emit(eventName, path5);
|
|
11104
|
+
this._closePath(path5);
|
|
10735
11105
|
}
|
|
10736
11106
|
/**
|
|
10737
11107
|
* Closes all watchers for a path
|
|
10738
11108
|
*/
|
|
10739
|
-
_closePath(
|
|
10740
|
-
this._closeFile(
|
|
10741
|
-
const dir = sp2.dirname(
|
|
10742
|
-
this._getWatchedDir(dir).remove(sp2.basename(
|
|
11109
|
+
_closePath(path5) {
|
|
11110
|
+
this._closeFile(path5);
|
|
11111
|
+
const dir = sp2.dirname(path5);
|
|
11112
|
+
this._getWatchedDir(dir).remove(sp2.basename(path5));
|
|
10743
11113
|
}
|
|
10744
11114
|
/**
|
|
10745
11115
|
* Closes only file-specific watchers
|
|
10746
11116
|
*/
|
|
10747
|
-
_closeFile(
|
|
10748
|
-
const closers = this._closers.get(
|
|
11117
|
+
_closeFile(path5) {
|
|
11118
|
+
const closers = this._closers.get(path5);
|
|
10749
11119
|
if (!closers)
|
|
10750
11120
|
return;
|
|
10751
11121
|
closers.forEach((closer) => closer());
|
|
10752
|
-
this._closers.delete(
|
|
11122
|
+
this._closers.delete(path5);
|
|
10753
11123
|
}
|
|
10754
|
-
_addPathCloser(
|
|
11124
|
+
_addPathCloser(path5, closer) {
|
|
10755
11125
|
if (!closer)
|
|
10756
11126
|
return;
|
|
10757
|
-
let list = this._closers.get(
|
|
11127
|
+
let list = this._closers.get(path5);
|
|
10758
11128
|
if (!list) {
|
|
10759
11129
|
list = [];
|
|
10760
|
-
this._closers.set(
|
|
11130
|
+
this._closers.set(path5, list);
|
|
10761
11131
|
}
|
|
10762
11132
|
list.push(closer);
|
|
10763
11133
|
}
|
|
@@ -10826,14 +11196,14 @@ function startWatcher(opts) {
|
|
|
10826
11196
|
const binding = pathBindings.get(removedPath);
|
|
10827
11197
|
if (!binding) return;
|
|
10828
11198
|
try {
|
|
10829
|
-
opts.archive.
|
|
11199
|
+
opts.archive.recordIngestionEvent({
|
|
10830
11200
|
agent: binding.plugin.id,
|
|
10831
11201
|
sourceId: binding.ref.sourceId,
|
|
10832
11202
|
sourcePath: removedPath,
|
|
10833
11203
|
eventType: "unlink_observed",
|
|
10834
11204
|
detail: { path: removedPath },
|
|
10835
11205
|
observedAt: /* @__PURE__ */ new Date()
|
|
10836
|
-
})
|
|
11206
|
+
});
|
|
10837
11207
|
} catch (err) {
|
|
10838
11208
|
onError(err);
|
|
10839
11209
|
}
|
|
@@ -10855,13 +11225,13 @@ function startWatcher(opts) {
|
|
|
10855
11225
|
}
|
|
10856
11226
|
return {
|
|
10857
11227
|
ready,
|
|
10858
|
-
notifyChange(
|
|
10859
|
-
if (watcher2) watcher2.emit("change",
|
|
10860
|
-
else scheduleIngest(
|
|
11228
|
+
notifyChange(path5) {
|
|
11229
|
+
if (watcher2) watcher2.emit("change", path5);
|
|
11230
|
+
else scheduleIngest(path5);
|
|
10861
11231
|
},
|
|
10862
|
-
notifyUnlink(
|
|
10863
|
-
if (watcher2) watcher2.emit("unlink",
|
|
10864
|
-
else recordUnlink(
|
|
11232
|
+
notifyUnlink(path5) {
|
|
11233
|
+
if (watcher2) watcher2.emit("unlink", path5);
|
|
11234
|
+
else recordUnlink(path5);
|
|
10865
11235
|
},
|
|
10866
11236
|
async close() {
|
|
10867
11237
|
closed = true;
|
|
@@ -10873,38 +11243,38 @@ function startWatcher(opts) {
|
|
|
10873
11243
|
}
|
|
10874
11244
|
|
|
10875
11245
|
// src/plugins/claude-code/plugin.ts
|
|
10876
|
-
import
|
|
10877
|
-
import
|
|
11246
|
+
import fs5 from "fs";
|
|
11247
|
+
import path3 from "path";
|
|
10878
11248
|
import readline from "readline";
|
|
10879
11249
|
var ClaudeCodePlugin = class {
|
|
10880
11250
|
id = "claude-code";
|
|
10881
11251
|
displayName = "Claude Code";
|
|
10882
11252
|
async *discover(env) {
|
|
10883
|
-
const projectsDir =
|
|
10884
|
-
if (!
|
|
10885
|
-
const projects =
|
|
11253
|
+
const projectsDir = path3.join(env.homeDir, ".claude", "projects");
|
|
11254
|
+
if (!fs5.existsSync(projectsDir)) return;
|
|
11255
|
+
const projects = fs5.readdirSync(projectsDir, { withFileTypes: true });
|
|
10886
11256
|
for (const project of projects) {
|
|
10887
11257
|
if (!project.isDirectory()) continue;
|
|
10888
|
-
const projectPath =
|
|
10889
|
-
const files =
|
|
11258
|
+
const projectPath = path3.join(projectsDir, project.name);
|
|
11259
|
+
const files = fs5.readdirSync(projectPath, { withFileTypes: true });
|
|
10890
11260
|
for (const file of files) {
|
|
10891
11261
|
if (!file.isFile() || !file.name.endsWith(".jsonl")) continue;
|
|
10892
|
-
const sourcePath =
|
|
11262
|
+
const sourcePath = path3.join(projectPath, file.name);
|
|
10893
11263
|
const sourceId = file.name.replace(/\.jsonl$/, "");
|
|
10894
11264
|
const cwd = await readCwdFromJsonl(sourcePath);
|
|
10895
11265
|
yield {
|
|
10896
11266
|
sourceId,
|
|
10897
11267
|
sourcePath,
|
|
10898
11268
|
watchPaths: [sourcePath],
|
|
10899
|
-
project: cwd ?
|
|
11269
|
+
project: cwd ? path3.basename(cwd) : void 0,
|
|
10900
11270
|
projectPath: cwd ?? void 0
|
|
10901
11271
|
};
|
|
10902
11272
|
}
|
|
10903
11273
|
}
|
|
10904
11274
|
}
|
|
10905
11275
|
async *extractRaw(ref) {
|
|
10906
|
-
if (!
|
|
10907
|
-
const stream =
|
|
11276
|
+
if (!fs5.existsSync(ref.sourcePath)) return;
|
|
11277
|
+
const stream = fs5.createReadStream(ref.sourcePath, { encoding: "utf-8" });
|
|
10908
11278
|
const rl = readline.createInterface({ input: stream, crlfDelay: Infinity });
|
|
10909
11279
|
let lineNo = 0;
|
|
10910
11280
|
for await (const line of rl) {
|
|
@@ -10953,7 +11323,7 @@ var ClaudeCodePlugin = class {
|
|
|
10953
11323
|
};
|
|
10954
11324
|
async function readCwdFromJsonl(sourcePath) {
|
|
10955
11325
|
try {
|
|
10956
|
-
const stream =
|
|
11326
|
+
const stream = fs5.createReadStream(sourcePath, { encoding: "utf-8" });
|
|
10957
11327
|
const rl = readline.createInterface({ input: stream, crlfDelay: Infinity });
|
|
10958
11328
|
try {
|
|
10959
11329
|
for await (const line of rl) {
|
|
@@ -11060,9 +11430,9 @@ Environment:
|
|
|
11060
11430
|
`;
|
|
11061
11431
|
|
|
11062
11432
|
// src/index.ts
|
|
11063
|
-
var __dirname =
|
|
11064
|
-
var pkgPath =
|
|
11065
|
-
var pkg = JSON.parse(
|
|
11433
|
+
var __dirname = path4.dirname(fileURLToPath2(import.meta.url));
|
|
11434
|
+
var pkgPath = path4.join(__dirname, "../../package.json");
|
|
11435
|
+
var pkg = JSON.parse(fs6.readFileSync(pkgPath, "utf-8"));
|
|
11066
11436
|
var action = parseCliArgs(process.argv.slice(2), {
|
|
11067
11437
|
PORT: process.env.PORT
|
|
11068
11438
|
});
|
|
@@ -11079,13 +11449,14 @@ if (action.kind === "error") {
|
|
|
11079
11449
|
process.exit(1);
|
|
11080
11450
|
}
|
|
11081
11451
|
updateNotifier({ pkg }).notify({ defer: false, isGlobal: true });
|
|
11082
|
-
var dataDir =
|
|
11083
|
-
var webDistDir =
|
|
11452
|
+
var dataDir = path4.join(os.homedir(), ".chat-logbook");
|
|
11453
|
+
var webDistDir = path4.join(__dirname, "../../web/dist");
|
|
11084
11454
|
var port = action.port;
|
|
11085
11455
|
var archive = createArchiveRepository({ dataDir });
|
|
11086
11456
|
var checkpoint = createCheckpointRepository({ dataDir });
|
|
11087
11457
|
var metadata = createMetadataRepository({ dataDir });
|
|
11088
|
-
var
|
|
11458
|
+
var tags2 = createTagRepository({ dataDir });
|
|
11459
|
+
var app = createApp({ archive, metadata, tags: tags2, webDistDir });
|
|
11089
11460
|
var initialIngest = startIngestionInBackground({
|
|
11090
11461
|
plugins,
|
|
11091
11462
|
archive,
|