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/api/dist/index.js CHANGED
@@ -5,11 +5,11 @@ var __export = (target, all) => {
5
5
  };
6
6
 
7
7
  // src/index.ts
8
- import fs7 from "fs";
8
+ import fs6 from "fs";
9
9
  import os from "os";
10
- import path5 from "path";
10
+ import path4 from "path";
11
11
  import { exec } from "child_process";
12
- import { fileURLToPath as fileURLToPath4 } from "url";
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 index = -1;
591
+ let index2 = -1;
592
592
  return dispatch(0);
593
593
  async function dispatch(i) {
594
- if (i <= index) {
594
+ if (i <= index2) {
595
595
  throw new Error("next() called multiple times");
596
596
  }
597
- index = i;
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, index) => {
696
- if (index === keys.length - 1) {
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 = (path6) => {
709
- const paths = path6.split("/");
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: path6 } = extractGroupsFromPath(routePath);
717
- const paths = splitPath(path6);
716
+ const { groups, path: path5 } = extractGroupsFromPath(routePath);
717
+ const paths = splitPath(path5);
718
718
  return replaceGroupMarks(paths, groups);
719
719
  };
720
- var extractGroupsFromPath = (path6) => {
720
+ var extractGroupsFromPath = (path5) => {
721
721
  const groups = [];
722
- path6 = path6.replace(/\{[^}]+\}/g, (match2, index) => {
723
- const mark = `@${index}`;
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: path6 };
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 path6 = url.slice(start, end);
785
- return tryDecodeURI(path6.includes("%25") ? path6.replace(/%25/g, "%2525") : path6);
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 = (path6) => {
803
- if (path6.charCodeAt(path6.length - 1) !== 63 || !path6.includes(":")) {
802
+ var checkOptionalParameter = (path5) => {
803
+ if (path5.charCodeAt(path5.length - 1) !== 63 || !path5.includes(":")) {
804
804
  return null;
805
805
  }
806
- const segments = path6.split("/");
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, path6 = "/", matchResult = [[]]) {
947
+ constructor(request, path5 = "/", matchResult = [[]]) {
948
948
  this.raw = request;
949
- this.path = path6;
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, path6, ...handlers) => {
1687
- for (const p of [path6].flat()) {
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(path6, app2) {
1745
- const subApp = this.basePath(path6);
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(path6) {
1771
+ basePath(path5) {
1772
1772
  const subApp = this.#clone();
1773
- subApp._basePath = mergePath(this._basePath, path6);
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(path6, applicationHandler, options) {
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, path6);
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(path6, "*"), handler);
1889
+ this.#addRoute(METHOD_NAME_ALL, mergePath(path5, "*"), handler);
1890
1890
  return this;
1891
1891
  }
1892
- #addRoute(method, path6, handler) {
1892
+ #addRoute(method, path5, handler) {
1893
1893
  method = method.toUpperCase();
1894
- path6 = mergePath(this._basePath, path6);
1895
- const r = { basePath: this._basePath, path: path6, method, handler };
1896
- this.router.add(method, path6, [handler, r]);
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 path6 = this.getPath(request, { env });
1910
- const matchResult = this.router.match(method, path6);
1909
+ const path5 = this.getPath(request, { env });
1910
+ const matchResult = this.router.match(method, path5);
1911
1911
  const c = new Context(request, {
1912
- path: path6,
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, path6) {
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 index = match3.indexOf("", 1);
2025
- return [matcher[1][index], match3];
2024
+ const index2 = match3.indexOf("", 1);
2025
+ return [matcher[1][index2], match3];
2026
2026
  });
2027
2027
  this.match = match2;
2028
- return match2(method, path6);
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, index, paramMap, context, pathErrorCheckOnly) {
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 = 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, index, paramMap, context, pathErrorCheckOnly);
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(path6, index, pathErrorCheckOnly) {
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
- path6 = path6.replace(/\{[^}]+\}/g, (m) => {
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 = path6.match(/(?::[^\/]+)|(?:\/\*$)|./g) || [];
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, index, paramAssoc, this.#context, pathErrorCheckOnly);
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(path6) {
2199
- return wildcardRegExpCache[path6] ??= new RegExp(
2200
- path6 === "*" ? "" : `^${path6.replace(
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, path6, handlers] = routesWithStaticPathFlag[i];
2222
+ const [pathErrorCheckOnly, path5, handlers] = routesWithStaticPathFlag[i];
2223
2223
  if (pathErrorCheckOnly) {
2224
- staticMap[path6] = [handlers.map(([h]) => [h, /* @__PURE__ */ Object.create(null)]), emptyParam];
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(path6, j, pathErrorCheckOnly);
2230
+ paramAssoc = trie.insert(path5, j, pathErrorCheckOnly);
2231
2231
  } catch (e) {
2232
- throw e === PATH_ERROR ? new UnsupportedPathError(path6) : e;
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, path6) {
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(path6)) {
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, path6, handler) {
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 (path6 === "/*") {
2301
- path6 = "*";
2300
+ if (path5 === "/*") {
2301
+ path5 = "*";
2302
2302
  }
2303
- const paramCount = (path6.match(/\/:/g) || []).length;
2304
- if (/\*$/.test(path6)) {
2305
- const re = buildWildcardRegExp(path6);
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][path6] ||= findMiddleware(middleware[m], path6) || findMiddleware(middleware[METHOD_NAME_ALL], path6) || [];
2308
+ middleware[m][path5] ||= findMiddleware(middleware[m], path5) || findMiddleware(middleware[METHOD_NAME_ALL], path5) || [];
2309
2309
  });
2310
2310
  } else {
2311
- middleware[method][path6] ||= findMiddleware(middleware[method], path6) || findMiddleware(middleware[METHOD_NAME_ALL], path6) || [];
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(path6) || [path6];
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((path6) => [path6, r[method][path6]]) : [];
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((path6) => [path6, r[METHOD_NAME_ALL][path6]])
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, path6, handler) {
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, path6, handler]);
2386
+ this.#routes.push([method, path5, handler]);
2387
2387
  }
2388
- match(method, path6) {
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, path6);
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, path6, handler) {
2453
+ insert(method, path5, handler) {
2454
2454
  this.#order = ++this.#order;
2455
2455
  let curNode = this;
2456
- const parts = splitRoutingPath(path6);
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, path6) {
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(path6);
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 = path6[0] === "/" ? 1 : 0;
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 = path6.substring(partOffsets[i]);
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, path6, handler) {
2612
- const results = checkOptionalParameter(path6);
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, path6, handler);
2619
+ this.#node.insert(method, path5, handler);
2620
2620
  }
2621
- match(method, path6) {
2622
- return this.#node.search(method, path6);
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 = (path6) => {
2753
+ var getStats = (path5) => {
2754
2754
  let stats;
2755
2755
  try {
2756
- stats = statSync(path6);
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 path6 = join(
2799
+ let path5 = join(
2800
2800
  root,
2801
2801
  !optionPath && options.rewriteRequestPath ? options.rewriteRequestPath(filename, c) : filename
2802
2802
  );
2803
- let stats = getStats(path6);
2803
+ let stats = getStats(path5);
2804
2804
  if (stats && stats.isDirectory()) {
2805
2805
  const indexFile = options.index ?? "index.html";
2806
- path6 = join(path6, indexFile);
2807
- stats = getStats(path6);
2806
+ path5 = join(path5, indexFile);
2807
+ stats = getStats(path5);
2808
2808
  }
2809
2809
  if (!stats) {
2810
- await options.onNotFound?.(path6, c);
2810
+ await options.onNotFound?.(path5, c);
2811
2811
  return next();
2812
2812
  }
2813
- const mimeType = getMimeType(path6);
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(path6 + ENCODINGS[encoding]);
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
- path6 = path6 + ENCODINGS[encoding];
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(path6)), 200);
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(path6, { start, end });
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?.(path6, c);
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: path6, field }, columnIndex) => {
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 path6.entries()) {
4189
- if (pathChunkIndex < path6.length - 1) {
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) && path6.length === 2) {
4198
- const objectName = path6[0];
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 [index, key] of leftKeys.entries()) {
4243
- if (key !== rightKeys[index]) {
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 primaryKey;
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 (primaryKey) {
4629
- tableConfig.primaryKey.push(...primaryKey);
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/archive/schema.ts
4758
- var schema_exports = {};
4759
- __export(schema_exports, {
4760
- archiveMeta: () => archiveMeta,
4761
- chats: () => chats,
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/sqlite-core/foreign-keys.js
4769
- var ForeignKeyBuilder2 = class {
4770
- static [entityKind] = "SQLiteForeignKeyBuilder";
4771
- /** @internal */
4772
- reference;
4773
- /** @internal */
4774
- _onUpdate;
4775
- /** @internal */
4776
- _onDelete;
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
- static [entityKind] = "SQLiteForeignKey";
4808
- reference;
4809
- onUpdate;
4810
- onDelete;
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 [index, joinMeta] of joins.entries()) {
5834
- if (index === 0) {
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 (index < joins.length - 1) {
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 [index, orderByValue] of orderBy.entries()) {
6222
+ for (const [index2, orderByValue] of orderBy.entries()) {
5868
6223
  orderByList.push(orderByValue);
5869
- if (index < orderBy.length - 1) {
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 [index, groupByValue] of groupBy.entries()) {
6277
+ for (const [index2, groupByValue] of groupBy.entries()) {
5923
6278
  groupByList.push(groupByValue);
5924
- if (index < groupBy.length - 1) {
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 crypto3 from "crypto";
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: crypto3.createHash("sha256").update(query).digest("hex")
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/archive/chat-id.ts
8604
- import crypto4 from "crypto";
8605
- var CROCKFORD_ALPHABET = "0123456789abcdefghjkmnpqrstvwxyz";
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, "../../drizzle/archive"),
8631
- path.join(here, "./drizzle/archive")
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("Could not locate archive drizzle migrations folder");
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
- fs2.mkdirSync(dataDir2, { recursive: true });
8643
- const sqlite = new Database(path.join(dataDir2, "archive.db"));
8644
- const db = drizzle(sqlite, { schema: schema_exports });
8645
- migrate(db, { migrationsFolder: resolveMigrationsFolder() });
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 generateChatId({
8672
- isTaken: (candidate) => db.select({ id: chats.id }).from(chats).where(eq(chats.chatId, candidate)).get() !== void 0
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
- fs3.mkdirSync(dataDir2, { recursive: true });
8725
- const sqlite = new Database2(path2.join(dataDir2, "checkpoint.db"));
8726
- const db = drizzle(sqlite, { schema: schema_exports2 });
8727
- migrate(db, { migrationsFolder: resolveMigrationsFolder2() });
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 fs4 from "fs";
8776
- import path3 from "path";
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 = path3.join(dataDir2, LEGACY_DB_FILE);
8809
- const current = path3.join(dataDir2, DB_FILE);
8810
- if (!fs4.existsSync(legacy)) return;
8811
- if (fs4.existsSync(current)) return;
8812
- fs4.renameSync(legacy, current);
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 CLAUDE_CODE_AGENT2 = "claude-code";
9167
+ var CLAUDE_CODE_AGENT = "claude-code";
8815
9168
  function createMetadataRepository({
8816
9169
  dataDir: dataDir2,
8817
9170
  lookupInternalId,
8818
- ensureChat: ensureChat2
9171
+ ensureChat
8819
9172
  }) {
8820
- fs4.mkdirSync(dataDir2, { recursive: true });
8821
9173
  migrateLegacyDbFile(dataDir2);
8822
- const sqlite = new Database3(path3.join(dataDir2, DB_FILE));
8823
- const db = drizzle(sqlite);
8824
- migrate(db, { migrationsFolder: resolveMigrationsFolder3() });
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, ensureChat2);
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, ensureChat2) {
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(CLAUDE_CODE_AGENT2, row.id);
9246
+ let target = lookupInternalId(CLAUDE_CODE_AGENT, row.id);
8883
9247
  if (target === null) {
8884
- if (!ensureChat2) continue;
8885
- target = ensureChat2(CLAUDE_CODE_AGENT2, row.id);
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 crypto6 from "crypto";
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 payloadJson = JSON.stringify(raw2.payload);
8923
- const payloadHash = crypto6.createHash("sha256").update(payloadJson).digest("hex");
8924
- const existing = opts.archive.db.select({ id: rawMessages.id }).from(rawMessages).where(
8925
- and(
8926
- eq(rawMessages.agent, plugin.id),
8927
- eq(rawMessages.sourceId, ref.sourceId),
8928
- eq(rawMessages.payloadHash, payloadHash)
8929
- )
8930
- ).get();
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 = upsertNormalized(
8950
- opts.archive,
8951
- plugin.id,
8952
- ref.sourceId,
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 fs5.statSync(p);
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 = (path6) => statMethod(path6, { bigint: true });
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: path6, depth } = par;
9173
- const slice = fil.splice(0, batch).map((dirent) => this._formatEntry(dirent, path6));
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(path6, depth) {
9583
+ async _exploreDir(path5, depth) {
9214
9584
  let files;
9215
9585
  try {
9216
- files = await readdir(path6, this._rdOptions);
9586
+ files = await readdir(path5, this._rdOptions);
9217
9587
  } catch (error) {
9218
9588
  this._onError(error);
9219
9589
  }
9220
- return { files, depth, path: path6 };
9590
+ return { files, depth, path: path5 };
9221
9591
  }
9222
- async _formatEntry(dirent, path6) {
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(path6, basename3));
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(path6, options, listener, errHandler, emitRaw) {
9996
+ function createFsWatchInstance(path5, options, listener, errHandler, emitRaw) {
9627
9997
  const handleEvent = (rawEvent, evPath) => {
9628
- listener(path6);
9629
- emitRaw(rawEvent, evPath, { watchedPath: path6 });
9630
- if (evPath && path6 !== evPath) {
9631
- fsWatchBroadcast(sp.resolve(path6, evPath), KEY_LISTENERS, sp.join(path6, evPath));
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(path6, {
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 = (path6, fullPath, options, handlers) => {
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(path6, options, listener, errHandler, rawEmitter);
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
- path6,
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(path6, "r");
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 = (path6, fullPath, options, handlers) => {
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(path6, curr));
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(path6, listener) {
10135
+ _watchWithNodeFs(path5, listener) {
9766
10136
  const opts = this.fsw.options;
9767
- const directory = sp.dirname(path6);
9768
- const basename3 = sp.basename(path6);
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(path6);
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(path6, absolutePath, options, {
10151
+ closer = setFsWatchFileListener(path5, absolutePath, options, {
9782
10152
  listener,
9783
10153
  rawEmitter: this.fsw._emitRaw
9784
10154
  });
9785
10155
  } else {
9786
- closer = setFsWatchListener(path6, absolutePath, options, {
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 (path6, newStats) => {
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(path6);
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(path6, closer2);
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, path6, item) {
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(path6);
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, path6, entry.stats);
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, path6, entry.stats);
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 path6 = sp.join(directory, item);
10283
+ let path5 = sp.join(directory, item);
9914
10284
  current.add(item);
9915
- if (entry.stats.isSymbolicLink() && await this._handleSymlink(entry, directory, path6, item)) {
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
- path6 = sp.join(dir, sp.relative(dir, path6));
9925
- this._addToNodeFs(path6, initialAdd, wh, depth + 1);
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(path6, initialAdd, priorWh, depth, target) {
10364
+ async _addToNodeFs(path5, initialAdd, priorWh, depth, target) {
9995
10365
  const ready = this.fsw._emitReady;
9996
- if (this.fsw._isIgnored(path6) || this.fsw.closed) {
10366
+ if (this.fsw._isIgnored(path5) || this.fsw.closed) {
9997
10367
  ready();
9998
10368
  return false;
9999
10369
  }
10000
- const wh = this.fsw._getWatchHelpers(path6);
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(path6);
10017
- const targetPath = follow ? await fsrealpath(path6) : path6;
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(path6) : path6;
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, path6, wh, targetPath);
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(path6), targetPath);
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(path6, closer);
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 path6;
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(path6) {
10093
- if (typeof path6 !== "string")
10462
+ function normalizePath(path5) {
10463
+ if (typeof path5 !== "string")
10094
10464
  throw new Error("string expected");
10095
- path6 = sp2.normalize(path6);
10096
- path6 = path6.replace(/\\/g, "/");
10465
+ path5 = sp2.normalize(path5);
10466
+ path5 = path5.replace(/\\/g, "/");
10097
10467
  let prepend = false;
10098
- if (path6.startsWith("//"))
10468
+ if (path5.startsWith("//"))
10099
10469
  prepend = true;
10100
- path6 = path6.replace(DOUBLE_SLASH_RE, "/");
10470
+ path5 = path5.replace(DOUBLE_SLASH_RE, "/");
10101
10471
  if (prepend)
10102
- path6 = "/" + path6;
10103
- return path6;
10472
+ path5 = "/" + path5;
10473
+ return path5;
10104
10474
  }
10105
10475
  function matchPatterns(patterns, testString, stats) {
10106
- const path6 = normalizePath(testString);
10107
- for (let index = 0; index < patterns.length; index++) {
10108
- const pattern = patterns[index];
10109
- if (pattern(path6, stats)) {
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 = (path6) => toUnix(sp2.normalize(toUnix(path6)));
10148
- var normalizeIgnored = (cwd = "") => (path6) => {
10149
- if (typeof path6 === "string") {
10150
- return normalizePathToUnix(sp2.isAbsolute(path6) ? path6 : sp2.join(cwd, path6));
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 path6;
10522
+ return path5;
10153
10523
  }
10154
10524
  };
10155
- var getAbsolutePath = (path6, cwd) => {
10156
- if (sp2.isAbsolute(path6)) {
10157
- return path6;
10525
+ var getAbsolutePath = (path5, cwd) => {
10526
+ if (sp2.isAbsolute(path5)) {
10527
+ return path5;
10158
10528
  }
10159
- return sp2.join(cwd, path6);
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(path6, follow, fsw) {
10594
+ constructor(path5, follow, fsw) {
10225
10595
  this.fsw = fsw;
10226
- const watchPath = path6;
10227
- this.path = path6 = path6.replace(REPLACER_RE, "");
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((path6) => {
10368
- const absPath = getAbsolutePath(path6, cwd);
10737
+ paths = paths.map((path5) => {
10738
+ const absPath = getAbsolutePath(path5, cwd);
10369
10739
  return absPath;
10370
10740
  });
10371
10741
  }
10372
- paths.forEach((path6) => {
10373
- this._removeIgnoredPath(path6);
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 (path6) => {
10380
- const res = await this._nodeFsHandler._addToNodeFs(path6, !_internal, void 0, 0, _origAdd);
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((path6) => {
10403
- if (!sp2.isAbsolute(path6) && !this._closers.has(path6)) {
10772
+ paths.forEach((path5) => {
10773
+ if (!sp2.isAbsolute(path5) && !this._closers.has(path5)) {
10404
10774
  if (cwd)
10405
- path6 = sp2.join(cwd, path6);
10406
- path6 = sp2.resolve(path6);
10775
+ path5 = sp2.join(cwd, path5);
10776
+ path5 = sp2.resolve(path5);
10407
10777
  }
10408
- this._closePath(path6);
10409
- this._addIgnoredPath(path6);
10410
- if (this._watched.has(path6)) {
10778
+ this._closePath(path5);
10779
+ this._addIgnoredPath(path5);
10780
+ if (this._watched.has(path5)) {
10411
10781
  this._addIgnoredPath({
10412
- path: path6,
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 index = key || ONE_DOT;
10457
- watchList[index] = entry.getChildren().sort();
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, path6, stats) {
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
- path6 = sp2.normalize(path6);
10851
+ path5 = sp2.normalize(path5);
10482
10852
  if (opts.cwd)
10483
- path6 = sp2.relative(opts.cwd, path6);
10484
- const args = [path6];
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(path6))) {
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(path6, [event, ...args]);
10865
+ this._pendingUnlinks.set(path5, [event, ...args]);
10496
10866
  setTimeout(() => {
10497
- this._pendingUnlinks.forEach((entry, path7) => {
10867
+ this._pendingUnlinks.forEach((entry, path6) => {
10498
10868
  this.emit(...entry);
10499
10869
  this.emit(EVENTS.ALL, ...entry);
10500
- this._pendingUnlinks.delete(path7);
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(path6)) {
10875
+ if (event === EVENTS.ADD && this._pendingUnlinks.has(path5)) {
10506
10876
  event = EVENTS.CHANGE;
10507
- this._pendingUnlinks.delete(path6);
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(path6, awf.stabilityThreshold, event, awfEmit);
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, path6, 50);
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, path6) : path6;
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, path6, timeout) {
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(path6);
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(path6);
10949
+ const item = action2.get(path5);
10580
10950
  const count = item ? item.count : 0;
10581
- action2.delete(path6);
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(path6, thr);
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(path6, threshold, event, awfEmit) {
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 = path6;
10610
- if (this.options.cwd && !sp2.isAbsolute(path6)) {
10611
- fullPath = sp2.join(this.options.cwd, path6);
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(path6)) {
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(path6).lastChange = now2;
10994
+ writes.get(path5).lastChange = now2;
10625
10995
  }
10626
- const pw = writes.get(path6);
10996
+ const pw = writes.get(path5);
10627
10997
  const df = now2 - pw.lastChange;
10628
10998
  if (df >= threshold) {
10629
- writes.delete(path6);
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(path6)) {
10637
- writes.set(path6, {
11006
+ if (!writes.has(path5)) {
11007
+ writes.set(path5, {
10638
11008
  lastChange: now,
10639
11009
  cancelWait: () => {
10640
- writes.delete(path6);
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(path6, stats) {
10652
- if (this.options.atomic && DOT_RE.test(path6))
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(path6, stats);
11032
+ return this._userIgnored(path5, stats);
10663
11033
  }
10664
- _isntIgnored(path6, stat4) {
10665
- return !this._isIgnored(path6, stat4);
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(path6) {
10672
- return new WatchHelper(path6, this.options.followSymlinks, this);
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 path6 = sp2.join(directory, item);
10705
- const fullPath = sp2.resolve(path6);
10706
- isDirectory = isDirectory != null ? isDirectory : this._watched.has(path6) || this._watched.has(fullPath);
10707
- if (!this._throttle("remove", path6, 100))
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(path6);
11082
+ const wp = this._getWatchedDir(path5);
10713
11083
  const nestedDirectoryChildren = wp.getChildren();
10714
- nestedDirectoryChildren.forEach((nested) => this._remove(path6, nested));
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 = path6;
11091
+ let relPath = path5;
10722
11092
  if (this.options.cwd)
10723
- relPath = sp2.relative(this.options.cwd, path6);
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(path6);
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(path6))
10733
- this._emit(eventName, path6);
10734
- this._closePath(path6);
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(path6) {
10740
- this._closeFile(path6);
10741
- const dir = sp2.dirname(path6);
10742
- this._getWatchedDir(dir).remove(sp2.basename(path6));
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(path6) {
10748
- const closers = this._closers.get(path6);
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(path6);
11122
+ this._closers.delete(path5);
10753
11123
  }
10754
- _addPathCloser(path6, closer) {
11124
+ _addPathCloser(path5, closer) {
10755
11125
  if (!closer)
10756
11126
  return;
10757
- let list = this._closers.get(path6);
11127
+ let list = this._closers.get(path5);
10758
11128
  if (!list) {
10759
11129
  list = [];
10760
- this._closers.set(path6, list);
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.db.insert(ingestionEvents).values({
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
- }).run();
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(path6) {
10859
- if (watcher2) watcher2.emit("change", path6);
10860
- else scheduleIngest(path6);
11228
+ notifyChange(path5) {
11229
+ if (watcher2) watcher2.emit("change", path5);
11230
+ else scheduleIngest(path5);
10861
11231
  },
10862
- notifyUnlink(path6) {
10863
- if (watcher2) watcher2.emit("unlink", path6);
10864
- else recordUnlink(path6);
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 fs6 from "fs";
10877
- import path4 from "path";
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 = path4.join(env.homeDir, ".claude", "projects");
10884
- if (!fs6.existsSync(projectsDir)) return;
10885
- const projects = fs6.readdirSync(projectsDir, { withFileTypes: true });
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 = path4.join(projectsDir, project.name);
10889
- const files = fs6.readdirSync(projectPath, { withFileTypes: true });
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 = path4.join(projectPath, file.name);
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 ? path4.basename(cwd) : void 0,
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 (!fs6.existsSync(ref.sourcePath)) return;
10907
- const stream = fs6.createReadStream(ref.sourcePath, { encoding: "utf-8" });
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 = fs6.createReadStream(sourcePath, { encoding: "utf-8" });
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 = path5.dirname(fileURLToPath4(import.meta.url));
11064
- var pkgPath = path5.join(__dirname, "../../package.json");
11065
- var pkg = JSON.parse(fs7.readFileSync(pkgPath, "utf-8"));
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 = path5.join(os.homedir(), ".chat-logbook");
11083
- var webDistDir = path5.join(__dirname, "../../web/dist");
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 app = createApp({ archive, metadata, webDistDir });
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,