chat-logbook 0.11.0 → 0.12.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";
@@ -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) => {
722
+ path5 = path5.replace(/\{[^}]+\}/g, (match2, index) => {
723
723
  const mark = `@${index}`;
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];
@@ -2025,7 +2025,7 @@ function match(method, path6) {
2025
2025
  return [matcher[1][index], 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
@@ -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, index, 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--) {
@@ -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,217 @@ 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/archive/chat-id.ts
2864
+ import crypto3 from "crypto";
2865
+ var CROCKFORD_ALPHABET = "0123456789abcdefghjkmnpqrstvwxyz";
2866
+ var CHAT_ID_LENGTH = 6;
2867
+ var MAX_RETRIES = 5;
2868
+ var CHAT_ID_PREFIX = "clog_";
2869
+ var WIRE_FORM_RE = new RegExp(
2870
+ `^${CHAT_ID_PREFIX}[${CROCKFORD_ALPHABET}]{${CHAT_ID_LENGTH}}$`
2871
+ );
2872
+ function formatChatId(code) {
2873
+ return `${CHAT_ID_PREFIX}${code}`;
2874
+ }
2875
+ function parseChatId(wire) {
2876
+ if (!WIRE_FORM_RE.test(wire)) return null;
2877
+ return wire.slice(CHAT_ID_PREFIX.length);
2878
+ }
2879
+ function generateChatId({
2880
+ isTaken,
2881
+ randomIndex = () => crypto3.randomInt(CROCKFORD_ALPHABET.length)
2882
+ }) {
2883
+ for (let attempt = 0; attempt <= MAX_RETRIES; attempt++) {
2884
+ let code = "";
2885
+ for (let i = 0; i < CHAT_ID_LENGTH; i++) {
2886
+ code += CROCKFORD_ALPHABET[randomIndex()];
2887
+ }
2888
+ if (!isTaken(code)) {
2889
+ return code;
2890
+ }
2891
+ }
2892
+ throw new Error(
2893
+ `Failed to generate unique chat_id after ${MAX_RETRIES + 1} attempts`
2894
+ );
2895
+ }
2896
+
2897
+ // src/visibility.ts
2898
+ function loadChatVisibility(metadata2, opts) {
2899
+ const deleted = metadata2.listDeleted();
2900
+ const trashed = new Set(deleted.map((r) => r.id));
2901
+ const deletedAtById = new Map(
2902
+ deleted.map((r) => [r.id, r.deletedAt?.getTime() ?? null])
2903
+ );
2904
+ const showTrashed = opts.includeTrashed === true;
2905
+ return {
2906
+ isTrashed: (internalId) => trashed.has(internalId),
2907
+ isVisible: (internalId) => showTrashed || !trashed.has(internalId),
2908
+ deletedAt: (internalId) => deletedAtById.get(internalId) ?? null
2909
+ };
2910
+ }
2911
+
2912
+ // src/chat-reader.ts
2913
+ function toApiBlock(block) {
2914
+ if (block.type === "tool_result") {
2915
+ return {
2916
+ type: "tool_result",
2917
+ tool_use_id: String(block.toolUseId ?? ""),
2918
+ content: block.content
2919
+ };
2920
+ }
2921
+ return block;
2922
+ }
2923
+ function createChatReader({
2924
+ archive: archive2,
2925
+ metadata: metadata2
2926
+ }) {
2927
+ function findChat(id) {
2928
+ const code = parseChatId(id);
2929
+ if (code === null) return null;
2930
+ return archive2.read.findChatByChatId(code);
2931
+ }
2932
+ function deriveTitle(customTitle, firstUserText) {
2933
+ if (customTitle && customTitle.trim()) return customTitle;
2934
+ const text2 = firstUserText?.trim().split("\n")[0]?.trim();
2935
+ return text2 && text2.length > 0 ? text2 : "Untitled";
2936
+ }
2937
+ function key(agent, sourceId) {
2938
+ return [agent, sourceId].join("\0");
2939
+ }
2940
+ function listChats({
2941
+ includeTrashed
2942
+ }) {
2943
+ const visibility = loadChatVisibility(metadata2, { includeTrashed });
2944
+ const rows = archive2.read.listChatRows();
2945
+ const tsRangeByKey = new Map(
2946
+ archive2.read.listChatTsRanges().map((r) => [key(r.agent, r.sourceId), r])
2947
+ );
2948
+ const sourcePathByKey = new Map(
2949
+ archive2.read.listLatestRawSourcePaths().map((r) => [key(r.agent, r.sourceId), r.sourcePath])
2950
+ );
2951
+ const firstUserTextByKey = new Map(
2952
+ archive2.read.listFirstUserTexts().map((r) => [key(r.agent, r.sourceId), r.text])
2953
+ );
2954
+ const customTitleById = metadata2.listCustomTitles();
2955
+ const chats2 = [];
2956
+ for (const row of rows) {
2957
+ if (!visibility.isVisible(row.id)) continue;
2958
+ const isDeleted = visibility.isTrashed(row.id);
2959
+ const rowKey = key(row.agent, row.sourceId);
2960
+ const tsRange = tsRangeByKey.get(rowKey);
2961
+ const firstSeenAtMs = row.firstSeenAt.getTime();
2962
+ const chat = {
2963
+ id: formatChatId(row.chatId),
2964
+ sourceId: row.sourceId,
2965
+ agent: row.agent,
2966
+ title: deriveTitle(
2967
+ customTitleById.get(row.id),
2968
+ firstUserTextByKey.get(rowKey)
2969
+ ),
2970
+ project: row.project ?? "",
2971
+ projectPath: row.projectPath ?? null,
2972
+ sourceFilePath: sourcePathByKey.get(rowKey) ?? null,
2973
+ createdAt: tsRange?.minTs ?? firstSeenAtMs,
2974
+ updatedAt: tsRange?.maxTs ?? firstSeenAtMs,
2975
+ deletedAt: visibility.deletedAt(row.id)
2976
+ };
2977
+ if (isDeleted) chat.isDeleted = true;
2978
+ chats2.push(chat);
2979
+ }
2980
+ return chats2;
2981
+ }
2982
+ function getMessages(id, { includeTrashed }) {
2983
+ const row = findChat(id);
2984
+ if (!row) return null;
2985
+ const visibility = loadChatVisibility(metadata2, { includeTrashed });
2986
+ if (!visibility.isVisible(row.id)) return null;
2987
+ const rows = archive2.read.listMessagesByChat(row.agent, row.sourceId);
2988
+ return rows.map((m) => ({
2989
+ role: m.role,
2990
+ content: m.blocks.map(toApiBlock),
2991
+ timestamp: m.ts.toISOString()
2992
+ }));
2993
+ }
2994
+ return { listChats, getMessages, findChat };
2995
+ }
2996
+
2997
+ // src/app.ts
2998
+ function createApp({ archive: archive2, metadata: metadata2, webDistDir: webDistDir2 }) {
2999
+ const app2 = new Hono2();
3000
+ const reader = createChatReader({ archive: archive2, metadata: metadata2 });
3001
+ app2.get("/api/chats", (c) => {
3002
+ const chats2 = reader.listChats({
3003
+ includeTrashed: c.req.query("includeTrashed") === "true"
3004
+ });
3005
+ return c.json({ chats: chats2 });
3006
+ });
3007
+ app2.delete("/api/chats/:id", (c) => {
3008
+ const row = reader.findChat(c.req.param("id"));
3009
+ if (!row) {
3010
+ return c.json({ error: "Chat not found" }, 404);
3011
+ }
3012
+ metadata2.softDelete(row.id);
3013
+ return c.body(null, 204);
3014
+ });
3015
+ app2.post("/api/chats/:id/restore", (c) => {
3016
+ const row = reader.findChat(c.req.param("id"));
3017
+ if (!row) {
3018
+ return c.json({ error: "Chat not found" }, 404);
3019
+ }
3020
+ metadata2.restore(row.id);
3021
+ return c.body(null, 204);
3022
+ });
3023
+ app2.patch("/api/chats/:id/title", async (c) => {
3024
+ const row = reader.findChat(c.req.param("id"));
3025
+ if (!row) {
3026
+ return c.json({ error: "Chat not found" }, 404);
3027
+ }
3028
+ let body;
3029
+ try {
3030
+ body = await c.req.json();
3031
+ } catch {
3032
+ return c.json({ error: "Invalid JSON body" }, 400);
3033
+ }
3034
+ if (!body || typeof body !== "object" || typeof body.title !== "string") {
3035
+ return c.json({ error: "Invalid title" }, 400);
3036
+ }
3037
+ const raw2 = body.title;
3038
+ if (raw2.length > 200) {
3039
+ return c.json({ error: "Title too long" }, 400);
3040
+ }
3041
+ const trimmed = raw2.trim();
3042
+ metadata2.setCustomTitle(row.id, trimmed.length > 0 ? trimmed : null);
3043
+ return c.body(null, 204);
3044
+ });
3045
+ app2.get("/api/chats/:id", (c) => {
3046
+ const messages2 = reader.getMessages(c.req.param("id"), {
3047
+ includeTrashed: c.req.query("includeTrashed") === "true"
3048
+ });
3049
+ if (messages2 === null) {
3050
+ return c.json({ error: "Chat not found" }, 404);
3051
+ }
3052
+ return c.json({ messages: messages2 });
3053
+ });
3054
+ if (webDistDir2) {
3055
+ app2.use("*", serveStatic({ root: webDistDir2 }));
3056
+ app2.use("*", serveStatic({ root: webDistDir2, path: "index.html" }));
3057
+ }
3058
+ return app2;
3059
+ }
3060
+
3061
+ // src/archive/repository.ts
3062
+ import crypto5 from "crypto";
3063
+
2863
3064
  // ../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
3065
  var entityKind = /* @__PURE__ */ Symbol.for("drizzle:entityKind");
2865
3066
  function is(value, type) {
@@ -4173,7 +4374,7 @@ var QueryPromise = class {
4173
4374
  function mapResultRow(columns, row, joinsNotNullableMap) {
4174
4375
  const nullifyMap = {};
4175
4376
  const result = columns.reduce(
4176
- (result2, { path: path6, field }, columnIndex) => {
4377
+ (result2, { path: path5, field }, columnIndex) => {
4177
4378
  let decoder;
4178
4379
  if (is(field, Column)) {
4179
4380
  decoder = field;
@@ -4185,8 +4386,8 @@ function mapResultRow(columns, row, joinsNotNullableMap) {
4185
4386
  decoder = field.sql.decoder;
4186
4387
  }
4187
4388
  let node = result2;
4188
- for (const [pathChunkIndex, pathChunk] of path6.entries()) {
4189
- if (pathChunkIndex < path6.length - 1) {
4389
+ for (const [pathChunkIndex, pathChunk] of path5.entries()) {
4390
+ if (pathChunkIndex < path5.length - 1) {
4190
4391
  if (!(pathChunk in node)) {
4191
4392
  node[pathChunk] = {};
4192
4393
  }
@@ -4194,8 +4395,8 @@ function mapResultRow(columns, row, joinsNotNullableMap) {
4194
4395
  } else {
4195
4396
  const rawValue = row[columnIndex];
4196
4397
  const value = node[pathChunk] = rawValue === null ? null : decoder.mapFromDriverValue(rawValue);
4197
- if (joinsNotNullableMap && is(field, Column) && path6.length === 2) {
4198
- const objectName = path6[0];
4398
+ if (joinsNotNullableMap && is(field, Column) && path5.length === 2) {
4399
+ const objectName = path5[0];
4199
4400
  if (!(objectName in nullifyMap)) {
4200
4401
  nullifyMap[objectName] = value === null ? getTableName(field.table) : false;
4201
4402
  } else if (typeof nullifyMap[objectName] === "string" && nullifyMap[objectName] !== getTableName(field.table)) {
@@ -4754,16 +4955,82 @@ function mapRelationalRow(tablesConfig, tableConfig, row, buildQueryResultSelect
4754
4955
  return result;
4755
4956
  }
4756
4957
 
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
- });
4958
+ // src/storage/openStore.ts
4959
+ import fs2 from "fs";
4960
+ import path from "path";
4961
+ import { fileURLToPath } from "url";
4962
+ import Database from "better-sqlite3";
4963
+
4964
+ // ../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
4965
+ import Client from "better-sqlite3";
4966
+
4967
+ // ../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
4968
+ var SelectionProxyHandler = class _SelectionProxyHandler {
4969
+ static [entityKind] = "SelectionProxyHandler";
4970
+ config;
4971
+ constructor(config) {
4972
+ this.config = { ...config };
4973
+ }
4974
+ get(subquery, prop) {
4975
+ if (prop === "_") {
4976
+ return {
4977
+ ...subquery["_"],
4978
+ selectedFields: new Proxy(
4979
+ subquery._.selectedFields,
4980
+ this
4981
+ )
4982
+ };
4983
+ }
4984
+ if (prop === ViewBaseConfig) {
4985
+ return {
4986
+ ...subquery[ViewBaseConfig],
4987
+ selectedFields: new Proxy(
4988
+ subquery[ViewBaseConfig].selectedFields,
4989
+ this
4990
+ )
4991
+ };
4992
+ }
4993
+ if (typeof prop === "symbol") {
4994
+ return subquery[prop];
4995
+ }
4996
+ const columns = is(subquery, Subquery) ? subquery._.selectedFields : is(subquery, View) ? subquery[ViewBaseConfig].selectedFields : subquery;
4997
+ const value = columns[prop];
4998
+ if (is(value, SQL.Aliased)) {
4999
+ if (this.config.sqlAliasedBehavior === "sql" && !value.isSelectionField) {
5000
+ return value.sql;
5001
+ }
5002
+ const newValue = value.clone();
5003
+ newValue.isSelectionField = true;
5004
+ return newValue;
5005
+ }
5006
+ if (is(value, SQL)) {
5007
+ if (this.config.sqlBehavior === "sql") {
5008
+ return value;
5009
+ }
5010
+ throw new Error(
5011
+ `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.`
5012
+ );
5013
+ }
5014
+ if (is(value, Column)) {
5015
+ if (this.config.alias) {
5016
+ return new Proxy(
5017
+ value,
5018
+ new ColumnAliasProxyHandler(
5019
+ new Proxy(
5020
+ value.table,
5021
+ new TableAliasProxyHandler(this.config.alias, this.config.replaceOriginalName ?? false)
5022
+ )
5023
+ )
5024
+ );
5025
+ }
5026
+ return value;
5027
+ }
5028
+ if (typeof value !== "object" || value === null) {
5029
+ return value;
5030
+ }
5031
+ return new Proxy(value, new _SelectionProxyHandler(this.config));
5032
+ }
5033
+ };
4767
5034
 
4768
5035
  // ../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
5036
  var ForeignKeyBuilder2 = class {
@@ -5317,74 +5584,6 @@ function text(a, b = {}) {
5317
5584
  return new SQLiteTextBuilder(name, config);
5318
5585
  }
5319
5586
 
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
5587
  // ../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
5588
  function getSQLiteColumnBuilders() {
5390
5589
  return {
@@ -8168,242 +8367,6 @@ var SQLiteTransaction = class extends BaseSQLiteDatabase {
8168
8367
  }
8169
8368
  };
8170
8369
 
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
8370
  // ../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
8371
  var BetterSQLiteSession = class extends SQLiteSession {
8409
8372
  constructor(client, dialect, schema, options = {}) {
@@ -8563,7 +8526,7 @@ function drizzle(...params) {
8563
8526
  })(drizzle || (drizzle = {}));
8564
8527
 
8565
8528
  // ../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";
8529
+ import crypto4 from "crypto";
8567
8530
  import fs from "fs";
8568
8531
  function readMigrationFiles(config) {
8569
8532
  const migrationFolderTo = config.migrationsFolder;
@@ -8585,7 +8548,7 @@ function readMigrationFiles(config) {
8585
8548
  sql: result,
8586
8549
  bps: journalEntry.breakpoints,
8587
8550
  folderMillis: journalEntry.when,
8588
- hash: crypto3.createHash("sha256").update(query).digest("hex")
8551
+ hash: crypto4.createHash("sha256").update(query).digest("hex")
8589
8552
  });
8590
8553
  } catch {
8591
8554
  throw new Error(`No file ${migrationPath} found in ${migrationFolderTo} folder`);
@@ -8600,49 +8563,184 @@ function migrate(db, config) {
8600
8563
  db.dialect.migrate(migrations, db.session, config);
8601
8564
  }
8602
8565
 
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));
8566
+ // src/storage/openStore.ts
8567
+ function resolveMigrationsFolder(callerUrl, migrationsSubdir) {
8568
+ const here = path.dirname(fileURLToPath(callerUrl));
8629
8569
  const candidates = [
8630
- path.join(here, "../../drizzle/archive"),
8631
- path.join(here, "./drizzle/archive")
8570
+ path.join(here, "../..", migrationsSubdir),
8571
+ path.join(here, ".", migrationsSubdir)
8632
8572
  ];
8633
8573
  const found = candidates.find((p) => fs2.existsSync(p));
8634
8574
  if (!found) {
8635
- throw new Error("Could not locate archive drizzle migrations folder");
8575
+ throw new Error(`Could not locate migrations folder "${migrationsSubdir}"`);
8636
8576
  }
8637
8577
  return found;
8638
8578
  }
8579
+ function openStore({
8580
+ dataDir: dataDir2,
8581
+ dbFile,
8582
+ callerUrl,
8583
+ migrationsSubdir,
8584
+ schema
8585
+ }) {
8586
+ const migrationsFolder = resolveMigrationsFolder(callerUrl, migrationsSubdir);
8587
+ fs2.mkdirSync(dataDir2, { recursive: true });
8588
+ const sqlite = new Database(path.join(dataDir2, dbFile));
8589
+ const db = drizzle(sqlite, { schema });
8590
+ migrate(db, { migrationsFolder });
8591
+ return { db, sqlite };
8592
+ }
8593
+
8594
+ // src/archive/schema.ts
8595
+ var schema_exports = {};
8596
+ __export(schema_exports, {
8597
+ archiveMeta: () => archiveMeta,
8598
+ chats: () => chats,
8599
+ ingestionEvents: () => ingestionEvents,
8600
+ messages: () => messages,
8601
+ rawMessages: () => rawMessages,
8602
+ schemaVersion: () => schemaVersion
8603
+ });
8604
+ var archiveMeta = sqliteTable("archive_meta", {
8605
+ id: integer("id").primaryKey(),
8606
+ archiveUuid: text("archive_uuid").notNull(),
8607
+ createdAt: integer("created_at", { mode: "timestamp_ms" }).notNull()
8608
+ });
8609
+ var schemaVersion = sqliteTable("schema_version", {
8610
+ version: integer("version").primaryKey(),
8611
+ appliedAt: integer("applied_at", { mode: "timestamp_ms" }).notNull()
8612
+ });
8613
+ var chats = sqliteTable(
8614
+ "chats",
8615
+ {
8616
+ id: text("id").primaryKey(),
8617
+ chatId: text("chat_id").notNull().unique(),
8618
+ agent: text("agent").notNull(),
8619
+ sourceId: text("source_id").notNull(),
8620
+ firstSeenAt: integer("first_seen_at", { mode: "timestamp_ms" }).notNull(),
8621
+ project: text("project"),
8622
+ projectPath: text("project_path")
8623
+ },
8624
+ (t) => [uniqueIndex("chats_agent_source_idx").on(t.agent, t.sourceId)]
8625
+ );
8626
+ var rawMessages = sqliteTable(
8627
+ "raw_messages",
8628
+ {
8629
+ id: integer("id").primaryKey({ autoIncrement: true }),
8630
+ agent: text("agent").notNull(),
8631
+ sourceId: text("source_id").notNull(),
8632
+ sourcePath: text("source_path").notNull(),
8633
+ sourceLocator: text("source_locator").notNull(),
8634
+ rawPayload: text("raw_payload").notNull(),
8635
+ payloadHash: text("payload_hash").notNull(),
8636
+ ingestedAt: integer("ingested_at", { mode: "timestamp_ms" }).notNull()
8637
+ },
8638
+ (t) => [
8639
+ uniqueIndex("raw_messages_idem_idx").on(t.agent, t.sourceId, t.payloadHash)
8640
+ ]
8641
+ );
8642
+ var messages = sqliteTable(
8643
+ "messages",
8644
+ {
8645
+ id: integer("id").primaryKey({ autoIncrement: true }),
8646
+ agent: text("agent").notNull(),
8647
+ sourceId: text("source_id").notNull(),
8648
+ messageId: text("message_id").notNull(),
8649
+ role: text("role").notNull(),
8650
+ ts: integer("ts", { mode: "timestamp_ms" }).notNull(),
8651
+ text: text("text").notNull(),
8652
+ blocks: text("blocks", { mode: "json" }).notNull(),
8653
+ rawId: integer("raw_id").notNull().references(() => rawMessages.id)
8654
+ },
8655
+ (t) => [
8656
+ uniqueIndex("messages_canonical_idx").on(t.agent, t.sourceId, t.messageId)
8657
+ ]
8658
+ );
8659
+ var ingestionEvents = sqliteTable("ingestion_events", {
8660
+ id: integer("id").primaryKey({ autoIncrement: true }),
8661
+ agent: text("agent").notNull(),
8662
+ sourceId: text("source_id").notNull(),
8663
+ sourcePath: text("source_path").notNull(),
8664
+ eventType: text("event_type").notNull(),
8665
+ detail: text("detail", { mode: "json" }).notNull(),
8666
+ observedAt: integer("observed_at", { mode: "timestamp_ms" }).notNull()
8667
+ });
8668
+
8669
+ // src/archive/read-seam.ts
8670
+ function createArchiveReadSeam(db) {
8671
+ return {
8672
+ listChatRows() {
8673
+ return db.select().from(chats).all();
8674
+ },
8675
+ findChatBySourceId(sourceId) {
8676
+ return db.select().from(chats).where(eq(chats.sourceId, sourceId)).get() ?? null;
8677
+ },
8678
+ findChatByChatId(chatId) {
8679
+ return db.select().from(chats).where(eq(chats.chatId, chatId)).get() ?? null;
8680
+ },
8681
+ listMessagesByChat(agent, sourceId) {
8682
+ return db.select().from(messages).where(and(eq(messages.agent, agent), eq(messages.sourceId, sourceId))).orderBy(asc(messages.ts)).all();
8683
+ },
8684
+ listChatTsRanges() {
8685
+ return db.select({
8686
+ agent: messages.agent,
8687
+ sourceId: messages.sourceId,
8688
+ minTs: sql`min(${messages.ts})`,
8689
+ maxTs: sql`max(${messages.ts})`
8690
+ }).from(messages).groupBy(messages.agent, messages.sourceId).all();
8691
+ },
8692
+ listLatestRawSourcePaths() {
8693
+ const ranked = db.select({
8694
+ agent: rawMessages.agent,
8695
+ sourceId: rawMessages.sourceId,
8696
+ sourcePath: rawMessages.sourcePath,
8697
+ rn: sql`row_number() over (partition by ${rawMessages.agent}, ${rawMessages.sourceId} order by ${rawMessages.ingestedAt} desc)`.as(
8698
+ "rn"
8699
+ )
8700
+ }).from(rawMessages).as("ranked_raw");
8701
+ return db.select({
8702
+ agent: ranked.agent,
8703
+ sourceId: ranked.sourceId,
8704
+ sourcePath: ranked.sourcePath
8705
+ }).from(ranked).where(eq(ranked.rn, 1)).all();
8706
+ },
8707
+ listFirstUserTexts() {
8708
+ const ranked = db.select({
8709
+ agent: messages.agent,
8710
+ sourceId: messages.sourceId,
8711
+ text: messages.text,
8712
+ rn: sql`row_number() over (partition by ${messages.agent}, ${messages.sourceId} order by ${messages.ts} asc)`.as(
8713
+ "rn"
8714
+ )
8715
+ }).from(messages).where(eq(messages.role, "user")).as("ranked_user");
8716
+ return db.select({
8717
+ agent: ranked.agent,
8718
+ sourceId: ranked.sourceId,
8719
+ text: ranked.text
8720
+ }).from(ranked).where(eq(ranked.rn, 1)).all();
8721
+ },
8722
+ listIngestionEvents() {
8723
+ return db.select().from(ingestionEvents).all();
8724
+ }
8725
+ };
8726
+ }
8727
+
8728
+ // src/archive/repository.ts
8729
+ function parseTs(ts) {
8730
+ const d = new Date(ts);
8731
+ if (Number.isNaN(d.getTime())) return /* @__PURE__ */ new Date(0);
8732
+ return d;
8733
+ }
8639
8734
  function createArchiveRepository({
8640
8735
  dataDir: dataDir2
8641
8736
  }) {
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() });
8737
+ const { db, sqlite } = openStore({
8738
+ dataDir: dataDir2,
8739
+ dbFile: "archive.db",
8740
+ callerUrl: import.meta.url,
8741
+ migrationsSubdir: "drizzle/archive",
8742
+ schema: schema_exports
8743
+ });
8646
8744
  const drizzleMigrations = sqlite.prepare("SELECT id, created_at FROM __drizzle_migrations ORDER BY id ASC").all();
8647
8745
  for (const m of drizzleMigrations) {
8648
8746
  db.insert(schemaVersion).values({ version: m.id, appliedAt: new Date(m.created_at) }).onConflictDoNothing().run();
@@ -8655,8 +8753,13 @@ function createArchiveRepository({
8655
8753
  createdAt: /* @__PURE__ */ new Date()
8656
8754
  }).run();
8657
8755
  }
8756
+ function nextChatId() {
8757
+ return generateChatId({
8758
+ isTaken: (candidate) => db.select({ id: chats.id }).from(chats).where(eq(chats.chatId, candidate)).get() !== void 0
8759
+ });
8760
+ }
8658
8761
  return {
8659
- db,
8762
+ read: createArchiveReadSeam(db),
8660
8763
  getArchiveUuid() {
8661
8764
  const row = db.select().from(archiveMeta).get();
8662
8765
  if (!row) {
@@ -8668,9 +8771,100 @@ function createArchiveRepository({
8668
8771
  return db.select().from(schemaVersion).all().map((r) => ({ version: r.version, appliedAt: r.appliedAt }));
8669
8772
  },
8670
8773
  generateChatId() {
8671
- return generateChatId({
8672
- isTaken: (candidate) => db.select({ id: chats.id }).from(chats).where(eq(chats.chatId, candidate)).get() !== void 0
8673
- });
8774
+ return nextChatId();
8775
+ },
8776
+ ensureChat(agent, sourceId, firstSeenAt, project, projectPath) {
8777
+ const existingChat = db.select().from(chats).where(and(eq(chats.agent, agent), eq(chats.sourceId, sourceId))).get();
8778
+ if (existingChat) {
8779
+ const updates = {};
8780
+ if (project && existingChat.project !== project) {
8781
+ updates.project = project;
8782
+ }
8783
+ if (projectPath && existingChat.projectPath !== projectPath) {
8784
+ updates.projectPath = projectPath;
8785
+ }
8786
+ if (Object.keys(updates).length > 0) {
8787
+ db.update(chats).set(updates).where(eq(chats.id, existingChat.id)).run();
8788
+ }
8789
+ return existingChat.id;
8790
+ }
8791
+ const id = crypto5.randomUUID();
8792
+ db.insert(chats).values({
8793
+ id,
8794
+ chatId: nextChatId(),
8795
+ agent,
8796
+ sourceId,
8797
+ firstSeenAt,
8798
+ project: project ?? null,
8799
+ projectPath: projectPath ?? null
8800
+ }).run();
8801
+ return id;
8802
+ },
8803
+ insertRawMessage(input) {
8804
+ const payloadJson = JSON.stringify(input.payload);
8805
+ const payloadHash = crypto5.createHash("sha256").update(payloadJson).digest("hex");
8806
+ const existing2 = db.select({ id: rawMessages.id }).from(rawMessages).where(
8807
+ and(
8808
+ eq(rawMessages.agent, input.agent),
8809
+ eq(rawMessages.sourceId, input.sourceId),
8810
+ eq(rawMessages.payloadHash, payloadHash)
8811
+ )
8812
+ ).get();
8813
+ if (existing2) return { id: existing2.id, inserted: false };
8814
+ const inserted = db.insert(rawMessages).values({
8815
+ agent: input.agent,
8816
+ sourceId: input.sourceId,
8817
+ sourcePath: input.sourcePath,
8818
+ sourceLocator: input.sourceLocator,
8819
+ rawPayload: payloadJson,
8820
+ payloadHash,
8821
+ ingestedAt: input.ingestedAt
8822
+ }).returning({ id: rawMessages.id }).get();
8823
+ return { id: inserted.id, inserted: true };
8824
+ },
8825
+ upsertNormalizedMessage({ agent, sourceId, message, rawId }) {
8826
+ const existing2 = db.select().from(messages).where(
8827
+ and(
8828
+ eq(messages.agent, agent),
8829
+ eq(messages.sourceId, sourceId),
8830
+ eq(messages.messageId, message.messageId)
8831
+ )
8832
+ ).get();
8833
+ const ts = parseTs(message.ts);
8834
+ if (!existing2) {
8835
+ db.insert(messages).values({
8836
+ agent,
8837
+ sourceId,
8838
+ messageId: message.messageId,
8839
+ role: message.role,
8840
+ ts,
8841
+ text: message.text,
8842
+ blocks: message.blocks,
8843
+ rawId
8844
+ }).run();
8845
+ return true;
8846
+ }
8847
+ if (ts.getTime() >= existing2.ts.getTime()) {
8848
+ db.update(messages).set({
8849
+ role: message.role,
8850
+ ts,
8851
+ text: message.text,
8852
+ blocks: message.blocks,
8853
+ rawId
8854
+ }).where(eq(messages.id, existing2.id)).run();
8855
+ return true;
8856
+ }
8857
+ return false;
8858
+ },
8859
+ recordIngestionEvent(event) {
8860
+ db.insert(ingestionEvents).values({
8861
+ agent: event.agent,
8862
+ sourceId: event.sourceId,
8863
+ sourcePath: event.sourcePath,
8864
+ eventType: event.eventType,
8865
+ detail: event.detail,
8866
+ observedAt: event.observedAt ?? /* @__PURE__ */ new Date()
8867
+ }).run();
8674
8868
  },
8675
8869
  close() {
8676
8870
  sqlite.close();
@@ -8678,12 +8872,6 @@ function createArchiveRepository({
8678
8872
  };
8679
8873
  }
8680
8874
 
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
8875
  // src/checkpoint/schema.ts
8688
8876
  var schema_exports2 = {};
8689
8877
  __export(schema_exports2, {
@@ -8706,25 +8894,16 @@ var chatScanState = sqliteTable(
8706
8894
  );
8707
8895
 
8708
8896
  // 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
8897
  function createCheckpointRepository({
8722
8898
  dataDir: dataDir2
8723
8899
  }) {
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() });
8900
+ const { db, sqlite } = openStore({
8901
+ dataDir: dataDir2,
8902
+ dbFile: "checkpoint.db",
8903
+ callerUrl: import.meta.url,
8904
+ migrationsSubdir: "drizzle/checkpoint",
8905
+ schema: schema_exports2
8906
+ });
8728
8907
  return {
8729
8908
  db,
8730
8909
  getScanState(agent, sourceId) {
@@ -8772,12 +8951,14 @@ function createCheckpointRepository({
8772
8951
  }
8773
8952
 
8774
8953
  // 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";
8954
+ import fs3 from "fs";
8955
+ import path2 from "path";
8779
8956
 
8780
8957
  // src/metadata/schema.ts
8958
+ var schema_exports3 = {};
8959
+ __export(schema_exports3, {
8960
+ chatsMeta: () => chatsMeta
8961
+ });
8781
8962
  var chatsMeta = sqliteTable("chats_meta", {
8782
8963
  id: text("id").primaryKey(),
8783
8964
  isDeleted: integer("is_deleted", { mode: "boolean" }).notNull().default(false),
@@ -8790,40 +8971,31 @@ var chatsMeta = sqliteTable("chats_meta", {
8790
8971
  });
8791
8972
 
8792
8973
  // 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
8974
  var DB_FILE = "metadata.db";
8806
8975
  var LEGACY_DB_FILE = "data.db";
8807
8976
  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);
8977
+ const legacy = path2.join(dataDir2, LEGACY_DB_FILE);
8978
+ const current = path2.join(dataDir2, DB_FILE);
8979
+ if (!fs3.existsSync(legacy)) return;
8980
+ if (fs3.existsSync(current)) return;
8981
+ fs3.renameSync(legacy, current);
8813
8982
  }
8814
- var CLAUDE_CODE_AGENT2 = "claude-code";
8983
+ var CLAUDE_CODE_AGENT = "claude-code";
8815
8984
  function createMetadataRepository({
8816
8985
  dataDir: dataDir2,
8817
8986
  lookupInternalId,
8818
- ensureChat: ensureChat2
8987
+ ensureChat
8819
8988
  }) {
8820
- fs4.mkdirSync(dataDir2, { recursive: true });
8821
8989
  migrateLegacyDbFile(dataDir2);
8822
- const sqlite = new Database3(path3.join(dataDir2, DB_FILE));
8823
- const db = drizzle(sqlite);
8824
- migrate(db, { migrationsFolder: resolveMigrationsFolder3() });
8990
+ const { db, sqlite } = openStore({
8991
+ dataDir: dataDir2,
8992
+ dbFile: DB_FILE,
8993
+ callerUrl: import.meta.url,
8994
+ migrationsSubdir: "drizzle",
8995
+ schema: schema_exports3
8996
+ });
8825
8997
  if (lookupInternalId) {
8826
- rekeyLegacyRows(sqlite, db, lookupInternalId, ensureChat2);
8998
+ rekeyLegacyRows(sqlite, db, lookupInternalId, ensureChat);
8827
8999
  }
8828
9000
  return {
8829
9001
  softDelete(internalId) {
@@ -8859,6 +9031,14 @@ function createMetadataRepository({
8859
9031
  const row = db.select({ customTitle: chatsMeta.customTitle }).from(chatsMeta).where(eq(chatsMeta.id, internalId)).get();
8860
9032
  return row?.customTitle ?? null;
8861
9033
  },
9034
+ listCustomTitles() {
9035
+ const rows = db.select({ id: chatsMeta.id, customTitle: chatsMeta.customTitle }).from(chatsMeta).where(isNotNull(chatsMeta.customTitle)).all();
9036
+ const byId = /* @__PURE__ */ new Map();
9037
+ for (const row of rows) {
9038
+ if (row.customTitle !== null) byId.set(row.id, row.customTitle);
9039
+ }
9040
+ return byId;
9041
+ },
8862
9042
  setCustomTitle(internalId, title) {
8863
9043
  const now = /* @__PURE__ */ new Date();
8864
9044
  db.insert(chatsMeta).values({
@@ -8874,15 +9054,15 @@ function createMetadataRepository({
8874
9054
  };
8875
9055
  }
8876
9056
  var REKEY_USER_VERSION = 4;
8877
- function rekeyLegacyRows(sqlite, db, lookupInternalId, ensureChat2) {
9057
+ function rekeyLegacyRows(sqlite, db, lookupInternalId, ensureChat) {
8878
9058
  const current = sqlite.pragma("user_version", { simple: true });
8879
9059
  if (current >= REKEY_USER_VERSION) return;
8880
9060
  const rows = db.select({ id: chatsMeta.id }).from(chatsMeta).all();
8881
9061
  for (const row of rows) {
8882
- let target = lookupInternalId(CLAUDE_CODE_AGENT2, row.id);
9062
+ let target = lookupInternalId(CLAUDE_CODE_AGENT, row.id);
8883
9063
  if (target === null) {
8884
- if (!ensureChat2) continue;
8885
- target = ensureChat2(CLAUDE_CODE_AGENT2, row.id);
9064
+ if (!ensureChat) continue;
9065
+ target = ensureChat(CLAUDE_CODE_AGENT, row.id);
8886
9066
  }
8887
9067
  if (target === row.id) continue;
8888
9068
  db.update(chatsMeta).set({ id: target, updatedAt: /* @__PURE__ */ new Date() }).where(eq(chatsMeta.id, row.id)).run();
@@ -8891,8 +9071,7 @@ function rekeyLegacyRows(sqlite, db, lookupInternalId, ensureChat2) {
8891
9071
  }
8892
9072
 
8893
9073
  // src/ingestion/ingest.ts
8894
- import crypto6 from "crypto";
8895
- import fs5 from "fs";
9074
+ import fs4 from "fs";
8896
9075
  async function runIngestion(opts) {
8897
9076
  const now = opts.now ?? (() => /* @__PURE__ */ new Date());
8898
9077
  const result = {
@@ -8906,8 +9085,7 @@ async function runIngestion(opts) {
8906
9085
  result.scanned += 1;
8907
9086
  const stat4 = safeStat(ref.sourcePath);
8908
9087
  const prior = opts.checkpoint.getScanState(plugin.id, ref.sourceId);
8909
- ensureChat(
8910
- opts.archive,
9088
+ opts.archive.ensureChat(
8911
9089
  plugin.id,
8912
9090
  ref.sourceId,
8913
9091
  now(),
@@ -8919,40 +9097,23 @@ async function runIngestion(opts) {
8919
9097
  continue;
8920
9098
  }
8921
9099
  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
- }
9100
+ const { id: rawId, inserted } = opts.archive.insertRawMessage({
9101
+ agent: plugin.id,
9102
+ sourceId: ref.sourceId,
9103
+ sourcePath: raw2.sourcePath,
9104
+ sourceLocator: raw2.sourceLocator,
9105
+ payload: raw2.payload,
9106
+ ingestedAt: now()
9107
+ });
9108
+ if (inserted) result.rawInserted += 1;
8947
9109
  const normalized = plugin.normalize(raw2);
8948
9110
  if (!normalized) continue;
8949
- const upserted = upsertNormalized(
8950
- opts.archive,
8951
- plugin.id,
8952
- ref.sourceId,
8953
- normalized,
9111
+ const upserted = opts.archive.upsertNormalizedMessage({
9112
+ agent: plugin.id,
9113
+ sourceId: ref.sourceId,
9114
+ message: normalized,
8954
9115
  rawId
8955
- );
9116
+ });
8956
9117
  if (upserted) result.normalizedUpserted += 1;
8957
9118
  }
8958
9119
  if (stat4) {
@@ -8970,76 +9131,11 @@ async function runIngestion(opts) {
8970
9131
  }
8971
9132
  function safeStat(p) {
8972
9133
  try {
8973
- return fs5.statSync(p);
9134
+ return fs4.statSync(p);
8974
9135
  } catch {
8975
9136
  return null;
8976
9137
  }
8977
9138
  }
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
9139
 
9044
9140
  // src/ingestion/background.ts
9045
9141
  function startIngestionInBackground(opts, bg = {}) {
@@ -9144,7 +9240,7 @@ var ReaddirpStream = class extends Readable3 {
9144
9240
  this._directoryFilter = normalizeFilter(opts.directoryFilter);
9145
9241
  const statMethod = opts.lstat ? lstat : stat;
9146
9242
  if (wantBigintFsStats) {
9147
- this._stat = (path6) => statMethod(path6, { bigint: true });
9243
+ this._stat = (path5) => statMethod(path5, { bigint: true });
9148
9244
  } else {
9149
9245
  this._stat = statMethod;
9150
9246
  }
@@ -9169,8 +9265,8 @@ var ReaddirpStream = class extends Readable3 {
9169
9265
  const par = this.parent;
9170
9266
  const fil = par && par.files;
9171
9267
  if (fil && fil.length > 0) {
9172
- const { path: path6, depth } = par;
9173
- const slice = fil.splice(0, batch).map((dirent) => this._formatEntry(dirent, path6));
9268
+ const { path: path5, depth } = par;
9269
+ const slice = fil.splice(0, batch).map((dirent) => this._formatEntry(dirent, path5));
9174
9270
  const awaited = await Promise.all(slice);
9175
9271
  for (const entry of awaited) {
9176
9272
  if (!entry)
@@ -9210,20 +9306,20 @@ var ReaddirpStream = class extends Readable3 {
9210
9306
  this.reading = false;
9211
9307
  }
9212
9308
  }
9213
- async _exploreDir(path6, depth) {
9309
+ async _exploreDir(path5, depth) {
9214
9310
  let files;
9215
9311
  try {
9216
- files = await readdir(path6, this._rdOptions);
9312
+ files = await readdir(path5, this._rdOptions);
9217
9313
  } catch (error) {
9218
9314
  this._onError(error);
9219
9315
  }
9220
- return { files, depth, path: path6 };
9316
+ return { files, depth, path: path5 };
9221
9317
  }
9222
- async _formatEntry(dirent, path6) {
9318
+ async _formatEntry(dirent, path5) {
9223
9319
  let entry;
9224
9320
  const basename3 = this._isDirent ? dirent.name : dirent;
9225
9321
  try {
9226
- const fullPath = presolve(pjoin(path6, basename3));
9322
+ const fullPath = presolve(pjoin(path5, basename3));
9227
9323
  entry = { path: prelative(this._root, fullPath), fullPath, basename: basename3 };
9228
9324
  entry[this._statsProp] = this._isDirent ? dirent : await this._stat(fullPath);
9229
9325
  } catch (err) {
@@ -9623,16 +9719,16 @@ var delFromSet = (main, prop, item) => {
9623
9719
  };
9624
9720
  var isEmptySet = (val) => val instanceof Set ? val.size === 0 : !val;
9625
9721
  var FsWatchInstances = /* @__PURE__ */ new Map();
9626
- function createFsWatchInstance(path6, options, listener, errHandler, emitRaw) {
9722
+ function createFsWatchInstance(path5, options, listener, errHandler, emitRaw) {
9627
9723
  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));
9724
+ listener(path5);
9725
+ emitRaw(rawEvent, evPath, { watchedPath: path5 });
9726
+ if (evPath && path5 !== evPath) {
9727
+ fsWatchBroadcast(sp.resolve(path5, evPath), KEY_LISTENERS, sp.join(path5, evPath));
9632
9728
  }
9633
9729
  };
9634
9730
  try {
9635
- return fs_watch(path6, {
9731
+ return fs_watch(path5, {
9636
9732
  persistent: options.persistent
9637
9733
  }, handleEvent);
9638
9734
  } catch (error) {
@@ -9648,12 +9744,12 @@ var fsWatchBroadcast = (fullPath, listenerType, val1, val2, val3) => {
9648
9744
  listener(val1, val2, val3);
9649
9745
  });
9650
9746
  };
9651
- var setFsWatchListener = (path6, fullPath, options, handlers) => {
9747
+ var setFsWatchListener = (path5, fullPath, options, handlers) => {
9652
9748
  const { listener, errHandler, rawEmitter } = handlers;
9653
9749
  let cont = FsWatchInstances.get(fullPath);
9654
9750
  let watcher2;
9655
9751
  if (!options.persistent) {
9656
- watcher2 = createFsWatchInstance(path6, options, listener, errHandler, rawEmitter);
9752
+ watcher2 = createFsWatchInstance(path5, options, listener, errHandler, rawEmitter);
9657
9753
  if (!watcher2)
9658
9754
  return;
9659
9755
  return watcher2.close.bind(watcher2);
@@ -9664,7 +9760,7 @@ var setFsWatchListener = (path6, fullPath, options, handlers) => {
9664
9760
  addAndConvert(cont, KEY_RAW, rawEmitter);
9665
9761
  } else {
9666
9762
  watcher2 = createFsWatchInstance(
9667
- path6,
9763
+ path5,
9668
9764
  options,
9669
9765
  fsWatchBroadcast.bind(null, fullPath, KEY_LISTENERS),
9670
9766
  errHandler,
@@ -9679,7 +9775,7 @@ var setFsWatchListener = (path6, fullPath, options, handlers) => {
9679
9775
  cont.watcherUnusable = true;
9680
9776
  if (isWindows && error.code === "EPERM") {
9681
9777
  try {
9682
- const fd = await open(path6, "r");
9778
+ const fd = await open(path5, "r");
9683
9779
  await fd.close();
9684
9780
  broadcastErr(error);
9685
9781
  } catch (err) {
@@ -9710,7 +9806,7 @@ var setFsWatchListener = (path6, fullPath, options, handlers) => {
9710
9806
  };
9711
9807
  };
9712
9808
  var FsWatchFileInstances = /* @__PURE__ */ new Map();
9713
- var setFsWatchFileListener = (path6, fullPath, options, handlers) => {
9809
+ var setFsWatchFileListener = (path5, fullPath, options, handlers) => {
9714
9810
  const { listener, rawEmitter } = handlers;
9715
9811
  let cont = FsWatchFileInstances.get(fullPath);
9716
9812
  const copts = cont && cont.options;
@@ -9732,7 +9828,7 @@ var setFsWatchFileListener = (path6, fullPath, options, handlers) => {
9732
9828
  });
9733
9829
  const currmtime = curr.mtimeMs;
9734
9830
  if (curr.size !== prev.size || currmtime > prev.mtimeMs || currmtime === 0) {
9735
- foreach(cont.listeners, (listener2) => listener2(path6, curr));
9831
+ foreach(cont.listeners, (listener2) => listener2(path5, curr));
9736
9832
  }
9737
9833
  })
9738
9834
  };
@@ -9762,13 +9858,13 @@ var NodeFsHandler = class {
9762
9858
  * @param listener on fs change
9763
9859
  * @returns closer for the watcher instance
9764
9860
  */
9765
- _watchWithNodeFs(path6, listener) {
9861
+ _watchWithNodeFs(path5, listener) {
9766
9862
  const opts = this.fsw.options;
9767
- const directory = sp.dirname(path6);
9768
- const basename3 = sp.basename(path6);
9863
+ const directory = sp.dirname(path5);
9864
+ const basename3 = sp.basename(path5);
9769
9865
  const parent = this.fsw._getWatchedDir(directory);
9770
9866
  parent.add(basename3);
9771
- const absolutePath = sp.resolve(path6);
9867
+ const absolutePath = sp.resolve(path5);
9772
9868
  const options = {
9773
9869
  persistent: opts.persistent
9774
9870
  };
@@ -9778,12 +9874,12 @@ var NodeFsHandler = class {
9778
9874
  if (opts.usePolling) {
9779
9875
  const enableBin = opts.interval !== opts.binaryInterval;
9780
9876
  options.interval = enableBin && isBinaryPath(basename3) ? opts.binaryInterval : opts.interval;
9781
- closer = setFsWatchFileListener(path6, absolutePath, options, {
9877
+ closer = setFsWatchFileListener(path5, absolutePath, options, {
9782
9878
  listener,
9783
9879
  rawEmitter: this.fsw._emitRaw
9784
9880
  });
9785
9881
  } else {
9786
- closer = setFsWatchListener(path6, absolutePath, options, {
9882
+ closer = setFsWatchListener(path5, absolutePath, options, {
9787
9883
  listener,
9788
9884
  errHandler: this._boundHandleError,
9789
9885
  rawEmitter: this.fsw._emitRaw
@@ -9805,7 +9901,7 @@ var NodeFsHandler = class {
9805
9901
  let prevStats = stats;
9806
9902
  if (parent.has(basename3))
9807
9903
  return;
9808
- const listener = async (path6, newStats) => {
9904
+ const listener = async (path5, newStats) => {
9809
9905
  if (!this.fsw._throttle(THROTTLE_MODE_WATCH, file, 5))
9810
9906
  return;
9811
9907
  if (!newStats || newStats.mtimeMs === 0) {
@@ -9819,11 +9915,11 @@ var NodeFsHandler = class {
9819
9915
  this.fsw._emit(EV.CHANGE, file, newStats2);
9820
9916
  }
9821
9917
  if ((isMacos || isLinux || isFreeBSD) && prevStats.ino !== newStats2.ino) {
9822
- this.fsw._closeFile(path6);
9918
+ this.fsw._closeFile(path5);
9823
9919
  prevStats = newStats2;
9824
9920
  const closer2 = this._watchWithNodeFs(file, listener);
9825
9921
  if (closer2)
9826
- this.fsw._addPathCloser(path6, closer2);
9922
+ this.fsw._addPathCloser(path5, closer2);
9827
9923
  } else {
9828
9924
  prevStats = newStats2;
9829
9925
  }
@@ -9855,7 +9951,7 @@ var NodeFsHandler = class {
9855
9951
  * @param item basename of this item
9856
9952
  * @returns true if no more processing is needed for this entry.
9857
9953
  */
9858
- async _handleSymlink(entry, directory, path6, item) {
9954
+ async _handleSymlink(entry, directory, path5, item) {
9859
9955
  if (this.fsw.closed) {
9860
9956
  return;
9861
9957
  }
@@ -9865,7 +9961,7 @@ var NodeFsHandler = class {
9865
9961
  this.fsw._incrReadyCount();
9866
9962
  let linkPath;
9867
9963
  try {
9868
- linkPath = await fsrealpath(path6);
9964
+ linkPath = await fsrealpath(path5);
9869
9965
  } catch (e) {
9870
9966
  this.fsw._emitReady();
9871
9967
  return true;
@@ -9875,12 +9971,12 @@ var NodeFsHandler = class {
9875
9971
  if (dir.has(item)) {
9876
9972
  if (this.fsw._symlinkPaths.get(full) !== linkPath) {
9877
9973
  this.fsw._symlinkPaths.set(full, linkPath);
9878
- this.fsw._emit(EV.CHANGE, path6, entry.stats);
9974
+ this.fsw._emit(EV.CHANGE, path5, entry.stats);
9879
9975
  }
9880
9976
  } else {
9881
9977
  dir.add(item);
9882
9978
  this.fsw._symlinkPaths.set(full, linkPath);
9883
- this.fsw._emit(EV.ADD, path6, entry.stats);
9979
+ this.fsw._emit(EV.ADD, path5, entry.stats);
9884
9980
  }
9885
9981
  this.fsw._emitReady();
9886
9982
  return true;
@@ -9910,9 +10006,9 @@ var NodeFsHandler = class {
9910
10006
  return;
9911
10007
  }
9912
10008
  const item = entry.path;
9913
- let path6 = sp.join(directory, item);
10009
+ let path5 = sp.join(directory, item);
9914
10010
  current.add(item);
9915
- if (entry.stats.isSymbolicLink() && await this._handleSymlink(entry, directory, path6, item)) {
10011
+ if (entry.stats.isSymbolicLink() && await this._handleSymlink(entry, directory, path5, item)) {
9916
10012
  return;
9917
10013
  }
9918
10014
  if (this.fsw.closed) {
@@ -9921,8 +10017,8 @@ var NodeFsHandler = class {
9921
10017
  }
9922
10018
  if (item === target || !target && !previous.has(item)) {
9923
10019
  this.fsw._incrReadyCount();
9924
- path6 = sp.join(dir, sp.relative(dir, path6));
9925
- this._addToNodeFs(path6, initialAdd, wh, depth + 1);
10020
+ path5 = sp.join(dir, sp.relative(dir, path5));
10021
+ this._addToNodeFs(path5, initialAdd, wh, depth + 1);
9926
10022
  }
9927
10023
  }).on(EV.ERROR, this._boundHandleError);
9928
10024
  return new Promise((resolve3, reject) => {
@@ -9991,13 +10087,13 @@ var NodeFsHandler = class {
9991
10087
  * @param depth Child path actually targeted for watch
9992
10088
  * @param target Child path actually targeted for watch
9993
10089
  */
9994
- async _addToNodeFs(path6, initialAdd, priorWh, depth, target) {
10090
+ async _addToNodeFs(path5, initialAdd, priorWh, depth, target) {
9995
10091
  const ready = this.fsw._emitReady;
9996
- if (this.fsw._isIgnored(path6) || this.fsw.closed) {
10092
+ if (this.fsw._isIgnored(path5) || this.fsw.closed) {
9997
10093
  ready();
9998
10094
  return false;
9999
10095
  }
10000
- const wh = this.fsw._getWatchHelpers(path6);
10096
+ const wh = this.fsw._getWatchHelpers(path5);
10001
10097
  if (priorWh) {
10002
10098
  wh.filterPath = (entry) => priorWh.filterPath(entry);
10003
10099
  wh.filterDir = (entry) => priorWh.filterDir(entry);
@@ -10013,8 +10109,8 @@ var NodeFsHandler = class {
10013
10109
  const follow = this.fsw.options.followSymlinks;
10014
10110
  let closer;
10015
10111
  if (stats.isDirectory()) {
10016
- const absPath = sp.resolve(path6);
10017
- const targetPath = follow ? await fsrealpath(path6) : path6;
10112
+ const absPath = sp.resolve(path5);
10113
+ const targetPath = follow ? await fsrealpath(path5) : path5;
10018
10114
  if (this.fsw.closed)
10019
10115
  return;
10020
10116
  closer = await this._handleDir(wh.watchPath, stats, initialAdd, depth, target, wh, targetPath);
@@ -10024,29 +10120,29 @@ var NodeFsHandler = class {
10024
10120
  this.fsw._symlinkPaths.set(absPath, targetPath);
10025
10121
  }
10026
10122
  } else if (stats.isSymbolicLink()) {
10027
- const targetPath = follow ? await fsrealpath(path6) : path6;
10123
+ const targetPath = follow ? await fsrealpath(path5) : path5;
10028
10124
  if (this.fsw.closed)
10029
10125
  return;
10030
10126
  const parent = sp.dirname(wh.watchPath);
10031
10127
  this.fsw._getWatchedDir(parent).add(wh.watchPath);
10032
10128
  this.fsw._emit(EV.ADD, wh.watchPath, stats);
10033
- closer = await this._handleDir(parent, stats, initialAdd, depth, path6, wh, targetPath);
10129
+ closer = await this._handleDir(parent, stats, initialAdd, depth, path5, wh, targetPath);
10034
10130
  if (this.fsw.closed)
10035
10131
  return;
10036
10132
  if (targetPath !== void 0) {
10037
- this.fsw._symlinkPaths.set(sp.resolve(path6), targetPath);
10133
+ this.fsw._symlinkPaths.set(sp.resolve(path5), targetPath);
10038
10134
  }
10039
10135
  } else {
10040
10136
  closer = this._handleFile(wh.watchPath, stats, initialAdd);
10041
10137
  }
10042
10138
  ready();
10043
10139
  if (closer)
10044
- this.fsw._addPathCloser(path6, closer);
10140
+ this.fsw._addPathCloser(path5, closer);
10045
10141
  return false;
10046
10142
  } catch (error) {
10047
10143
  if (this.fsw._handleError(error)) {
10048
10144
  ready();
10049
- return path6;
10145
+ return path5;
10050
10146
  }
10051
10147
  }
10052
10148
  }
@@ -10089,24 +10185,24 @@ function createPattern(matcher) {
10089
10185
  }
10090
10186
  return () => false;
10091
10187
  }
10092
- function normalizePath(path6) {
10093
- if (typeof path6 !== "string")
10188
+ function normalizePath(path5) {
10189
+ if (typeof path5 !== "string")
10094
10190
  throw new Error("string expected");
10095
- path6 = sp2.normalize(path6);
10096
- path6 = path6.replace(/\\/g, "/");
10191
+ path5 = sp2.normalize(path5);
10192
+ path5 = path5.replace(/\\/g, "/");
10097
10193
  let prepend = false;
10098
- if (path6.startsWith("//"))
10194
+ if (path5.startsWith("//"))
10099
10195
  prepend = true;
10100
- path6 = path6.replace(DOUBLE_SLASH_RE, "/");
10196
+ path5 = path5.replace(DOUBLE_SLASH_RE, "/");
10101
10197
  if (prepend)
10102
- path6 = "/" + path6;
10103
- return path6;
10198
+ path5 = "/" + path5;
10199
+ return path5;
10104
10200
  }
10105
10201
  function matchPatterns(patterns, testString, stats) {
10106
- const path6 = normalizePath(testString);
10202
+ const path5 = normalizePath(testString);
10107
10203
  for (let index = 0; index < patterns.length; index++) {
10108
10204
  const pattern = patterns[index];
10109
- if (pattern(path6, stats)) {
10205
+ if (pattern(path5, stats)) {
10110
10206
  return true;
10111
10207
  }
10112
10208
  }
@@ -10144,19 +10240,19 @@ var toUnix = (string) => {
10144
10240
  }
10145
10241
  return str;
10146
10242
  };
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));
10243
+ var normalizePathToUnix = (path5) => toUnix(sp2.normalize(toUnix(path5)));
10244
+ var normalizeIgnored = (cwd = "") => (path5) => {
10245
+ if (typeof path5 === "string") {
10246
+ return normalizePathToUnix(sp2.isAbsolute(path5) ? path5 : sp2.join(cwd, path5));
10151
10247
  } else {
10152
- return path6;
10248
+ return path5;
10153
10249
  }
10154
10250
  };
10155
- var getAbsolutePath = (path6, cwd) => {
10156
- if (sp2.isAbsolute(path6)) {
10157
- return path6;
10251
+ var getAbsolutePath = (path5, cwd) => {
10252
+ if (sp2.isAbsolute(path5)) {
10253
+ return path5;
10158
10254
  }
10159
- return sp2.join(cwd, path6);
10255
+ return sp2.join(cwd, path5);
10160
10256
  };
10161
10257
  var EMPTY_SET = Object.freeze(/* @__PURE__ */ new Set());
10162
10258
  var DirEntry = class {
@@ -10221,10 +10317,10 @@ var WatchHelper = class {
10221
10317
  dirParts;
10222
10318
  followSymlinks;
10223
10319
  statMethod;
10224
- constructor(path6, follow, fsw) {
10320
+ constructor(path5, follow, fsw) {
10225
10321
  this.fsw = fsw;
10226
- const watchPath = path6;
10227
- this.path = path6 = path6.replace(REPLACER_RE, "");
10322
+ const watchPath = path5;
10323
+ this.path = path5 = path5.replace(REPLACER_RE, "");
10228
10324
  this.watchPath = watchPath;
10229
10325
  this.fullWatchPath = sp2.resolve(watchPath);
10230
10326
  this.dirParts = [];
@@ -10364,20 +10460,20 @@ var FSWatcher = class extends EventEmitter {
10364
10460
  this._closePromise = void 0;
10365
10461
  let paths = unifyPaths(paths_);
10366
10462
  if (cwd) {
10367
- paths = paths.map((path6) => {
10368
- const absPath = getAbsolutePath(path6, cwd);
10463
+ paths = paths.map((path5) => {
10464
+ const absPath = getAbsolutePath(path5, cwd);
10369
10465
  return absPath;
10370
10466
  });
10371
10467
  }
10372
- paths.forEach((path6) => {
10373
- this._removeIgnoredPath(path6);
10468
+ paths.forEach((path5) => {
10469
+ this._removeIgnoredPath(path5);
10374
10470
  });
10375
10471
  this._userIgnored = void 0;
10376
10472
  if (!this._readyCount)
10377
10473
  this._readyCount = 0;
10378
10474
  this._readyCount += paths.length;
10379
- Promise.all(paths.map(async (path6) => {
10380
- const res = await this._nodeFsHandler._addToNodeFs(path6, !_internal, void 0, 0, _origAdd);
10475
+ Promise.all(paths.map(async (path5) => {
10476
+ const res = await this._nodeFsHandler._addToNodeFs(path5, !_internal, void 0, 0, _origAdd);
10381
10477
  if (res)
10382
10478
  this._emitReady();
10383
10479
  return res;
@@ -10399,17 +10495,17 @@ var FSWatcher = class extends EventEmitter {
10399
10495
  return this;
10400
10496
  const paths = unifyPaths(paths_);
10401
10497
  const { cwd } = this.options;
10402
- paths.forEach((path6) => {
10403
- if (!sp2.isAbsolute(path6) && !this._closers.has(path6)) {
10498
+ paths.forEach((path5) => {
10499
+ if (!sp2.isAbsolute(path5) && !this._closers.has(path5)) {
10404
10500
  if (cwd)
10405
- path6 = sp2.join(cwd, path6);
10406
- path6 = sp2.resolve(path6);
10501
+ path5 = sp2.join(cwd, path5);
10502
+ path5 = sp2.resolve(path5);
10407
10503
  }
10408
- this._closePath(path6);
10409
- this._addIgnoredPath(path6);
10410
- if (this._watched.has(path6)) {
10504
+ this._closePath(path5);
10505
+ this._addIgnoredPath(path5);
10506
+ if (this._watched.has(path5)) {
10411
10507
  this._addIgnoredPath({
10412
- path: path6,
10508
+ path: path5,
10413
10509
  recursive: true
10414
10510
  });
10415
10511
  }
@@ -10473,38 +10569,38 @@ var FSWatcher = class extends EventEmitter {
10473
10569
  * @param stats arguments to be passed with event
10474
10570
  * @returns the error if defined, otherwise the value of the FSWatcher instance's `closed` flag
10475
10571
  */
10476
- async _emit(event, path6, stats) {
10572
+ async _emit(event, path5, stats) {
10477
10573
  if (this.closed)
10478
10574
  return;
10479
10575
  const opts = this.options;
10480
10576
  if (isWindows)
10481
- path6 = sp2.normalize(path6);
10577
+ path5 = sp2.normalize(path5);
10482
10578
  if (opts.cwd)
10483
- path6 = sp2.relative(opts.cwd, path6);
10484
- const args = [path6];
10579
+ path5 = sp2.relative(opts.cwd, path5);
10580
+ const args = [path5];
10485
10581
  if (stats != null)
10486
10582
  args.push(stats);
10487
10583
  const awf = opts.awaitWriteFinish;
10488
10584
  let pw;
10489
- if (awf && (pw = this._pendingWrites.get(path6))) {
10585
+ if (awf && (pw = this._pendingWrites.get(path5))) {
10490
10586
  pw.lastChange = /* @__PURE__ */ new Date();
10491
10587
  return this;
10492
10588
  }
10493
10589
  if (opts.atomic) {
10494
10590
  if (event === EVENTS.UNLINK) {
10495
- this._pendingUnlinks.set(path6, [event, ...args]);
10591
+ this._pendingUnlinks.set(path5, [event, ...args]);
10496
10592
  setTimeout(() => {
10497
- this._pendingUnlinks.forEach((entry, path7) => {
10593
+ this._pendingUnlinks.forEach((entry, path6) => {
10498
10594
  this.emit(...entry);
10499
10595
  this.emit(EVENTS.ALL, ...entry);
10500
- this._pendingUnlinks.delete(path7);
10596
+ this._pendingUnlinks.delete(path6);
10501
10597
  });
10502
10598
  }, typeof opts.atomic === "number" ? opts.atomic : 100);
10503
10599
  return this;
10504
10600
  }
10505
- if (event === EVENTS.ADD && this._pendingUnlinks.has(path6)) {
10601
+ if (event === EVENTS.ADD && this._pendingUnlinks.has(path5)) {
10506
10602
  event = EVENTS.CHANGE;
10507
- this._pendingUnlinks.delete(path6);
10603
+ this._pendingUnlinks.delete(path5);
10508
10604
  }
10509
10605
  }
10510
10606
  if (awf && (event === EVENTS.ADD || event === EVENTS.CHANGE) && this._readyEmitted) {
@@ -10522,16 +10618,16 @@ var FSWatcher = class extends EventEmitter {
10522
10618
  this.emitWithAll(event, args);
10523
10619
  }
10524
10620
  };
10525
- this._awaitWriteFinish(path6, awf.stabilityThreshold, event, awfEmit);
10621
+ this._awaitWriteFinish(path5, awf.stabilityThreshold, event, awfEmit);
10526
10622
  return this;
10527
10623
  }
10528
10624
  if (event === EVENTS.CHANGE) {
10529
- const isThrottled = !this._throttle(EVENTS.CHANGE, path6, 50);
10625
+ const isThrottled = !this._throttle(EVENTS.CHANGE, path5, 50);
10530
10626
  if (isThrottled)
10531
10627
  return this;
10532
10628
  }
10533
10629
  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;
10630
+ const fullPath = opts.cwd ? sp2.join(opts.cwd, path5) : path5;
10535
10631
  let stats2;
10536
10632
  try {
10537
10633
  stats2 = await stat3(fullPath);
@@ -10562,23 +10658,23 @@ var FSWatcher = class extends EventEmitter {
10562
10658
  * @param timeout duration of time to suppress duplicate actions
10563
10659
  * @returns tracking object or false if action should be suppressed
10564
10660
  */
10565
- _throttle(actionType, path6, timeout) {
10661
+ _throttle(actionType, path5, timeout) {
10566
10662
  if (!this._throttled.has(actionType)) {
10567
10663
  this._throttled.set(actionType, /* @__PURE__ */ new Map());
10568
10664
  }
10569
10665
  const action2 = this._throttled.get(actionType);
10570
10666
  if (!action2)
10571
10667
  throw new Error("invalid throttle");
10572
- const actionPath = action2.get(path6);
10668
+ const actionPath = action2.get(path5);
10573
10669
  if (actionPath) {
10574
10670
  actionPath.count++;
10575
10671
  return false;
10576
10672
  }
10577
10673
  let timeoutObject;
10578
10674
  const clear = () => {
10579
- const item = action2.get(path6);
10675
+ const item = action2.get(path5);
10580
10676
  const count = item ? item.count : 0;
10581
- action2.delete(path6);
10677
+ action2.delete(path5);
10582
10678
  clearTimeout(timeoutObject);
10583
10679
  if (item)
10584
10680
  clearTimeout(item.timeoutObject);
@@ -10586,7 +10682,7 @@ var FSWatcher = class extends EventEmitter {
10586
10682
  };
10587
10683
  timeoutObject = setTimeout(clear, timeout);
10588
10684
  const thr = { timeoutObject, clear, count: 0 };
10589
- action2.set(path6, thr);
10685
+ action2.set(path5, thr);
10590
10686
  return thr;
10591
10687
  }
10592
10688
  _incrReadyCount() {
@@ -10600,44 +10696,44 @@ var FSWatcher = class extends EventEmitter {
10600
10696
  * @param event
10601
10697
  * @param awfEmit Callback to be called when ready for event to be emitted.
10602
10698
  */
10603
- _awaitWriteFinish(path6, threshold, event, awfEmit) {
10699
+ _awaitWriteFinish(path5, threshold, event, awfEmit) {
10604
10700
  const awf = this.options.awaitWriteFinish;
10605
10701
  if (typeof awf !== "object")
10606
10702
  return;
10607
10703
  const pollInterval = awf.pollInterval;
10608
10704
  let timeoutHandler;
10609
- let fullPath = path6;
10610
- if (this.options.cwd && !sp2.isAbsolute(path6)) {
10611
- fullPath = sp2.join(this.options.cwd, path6);
10705
+ let fullPath = path5;
10706
+ if (this.options.cwd && !sp2.isAbsolute(path5)) {
10707
+ fullPath = sp2.join(this.options.cwd, path5);
10612
10708
  }
10613
10709
  const now = /* @__PURE__ */ new Date();
10614
10710
  const writes = this._pendingWrites;
10615
10711
  function awaitWriteFinishFn(prevStat) {
10616
10712
  statcb(fullPath, (err, curStat) => {
10617
- if (err || !writes.has(path6)) {
10713
+ if (err || !writes.has(path5)) {
10618
10714
  if (err && err.code !== "ENOENT")
10619
10715
  awfEmit(err);
10620
10716
  return;
10621
10717
  }
10622
10718
  const now2 = Number(/* @__PURE__ */ new Date());
10623
10719
  if (prevStat && curStat.size !== prevStat.size) {
10624
- writes.get(path6).lastChange = now2;
10720
+ writes.get(path5).lastChange = now2;
10625
10721
  }
10626
- const pw = writes.get(path6);
10722
+ const pw = writes.get(path5);
10627
10723
  const df = now2 - pw.lastChange;
10628
10724
  if (df >= threshold) {
10629
- writes.delete(path6);
10725
+ writes.delete(path5);
10630
10726
  awfEmit(void 0, curStat);
10631
10727
  } else {
10632
10728
  timeoutHandler = setTimeout(awaitWriteFinishFn, pollInterval, curStat);
10633
10729
  }
10634
10730
  });
10635
10731
  }
10636
- if (!writes.has(path6)) {
10637
- writes.set(path6, {
10732
+ if (!writes.has(path5)) {
10733
+ writes.set(path5, {
10638
10734
  lastChange: now,
10639
10735
  cancelWait: () => {
10640
- writes.delete(path6);
10736
+ writes.delete(path5);
10641
10737
  clearTimeout(timeoutHandler);
10642
10738
  return event;
10643
10739
  }
@@ -10648,8 +10744,8 @@ var FSWatcher = class extends EventEmitter {
10648
10744
  /**
10649
10745
  * Determines whether user has asked to ignore this path.
10650
10746
  */
10651
- _isIgnored(path6, stats) {
10652
- if (this.options.atomic && DOT_RE.test(path6))
10747
+ _isIgnored(path5, stats) {
10748
+ if (this.options.atomic && DOT_RE.test(path5))
10653
10749
  return true;
10654
10750
  if (!this._userIgnored) {
10655
10751
  const { cwd } = this.options;
@@ -10659,17 +10755,17 @@ var FSWatcher = class extends EventEmitter {
10659
10755
  const list = [...ignoredPaths.map(normalizeIgnored(cwd)), ...ignored];
10660
10756
  this._userIgnored = anymatch(list, void 0);
10661
10757
  }
10662
- return this._userIgnored(path6, stats);
10758
+ return this._userIgnored(path5, stats);
10663
10759
  }
10664
- _isntIgnored(path6, stat4) {
10665
- return !this._isIgnored(path6, stat4);
10760
+ _isntIgnored(path5, stat4) {
10761
+ return !this._isIgnored(path5, stat4);
10666
10762
  }
10667
10763
  /**
10668
10764
  * Provides a set of common helpers and properties relating to symlink handling.
10669
10765
  * @param path file or directory pattern being watched
10670
10766
  */
10671
- _getWatchHelpers(path6) {
10672
- return new WatchHelper(path6, this.options.followSymlinks, this);
10767
+ _getWatchHelpers(path5) {
10768
+ return new WatchHelper(path5, this.options.followSymlinks, this);
10673
10769
  }
10674
10770
  // Directory helpers
10675
10771
  // -----------------
@@ -10701,63 +10797,63 @@ var FSWatcher = class extends EventEmitter {
10701
10797
  * @param item base path of item/directory
10702
10798
  */
10703
10799
  _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))
10800
+ const path5 = sp2.join(directory, item);
10801
+ const fullPath = sp2.resolve(path5);
10802
+ isDirectory = isDirectory != null ? isDirectory : this._watched.has(path5) || this._watched.has(fullPath);
10803
+ if (!this._throttle("remove", path5, 100))
10708
10804
  return;
10709
10805
  if (!isDirectory && this._watched.size === 1) {
10710
10806
  this.add(directory, item, true);
10711
10807
  }
10712
- const wp = this._getWatchedDir(path6);
10808
+ const wp = this._getWatchedDir(path5);
10713
10809
  const nestedDirectoryChildren = wp.getChildren();
10714
- nestedDirectoryChildren.forEach((nested) => this._remove(path6, nested));
10810
+ nestedDirectoryChildren.forEach((nested) => this._remove(path5, nested));
10715
10811
  const parent = this._getWatchedDir(directory);
10716
10812
  const wasTracked = parent.has(item);
10717
10813
  parent.remove(item);
10718
10814
  if (this._symlinkPaths.has(fullPath)) {
10719
10815
  this._symlinkPaths.delete(fullPath);
10720
10816
  }
10721
- let relPath = path6;
10817
+ let relPath = path5;
10722
10818
  if (this.options.cwd)
10723
- relPath = sp2.relative(this.options.cwd, path6);
10819
+ relPath = sp2.relative(this.options.cwd, path5);
10724
10820
  if (this.options.awaitWriteFinish && this._pendingWrites.has(relPath)) {
10725
10821
  const event = this._pendingWrites.get(relPath).cancelWait();
10726
10822
  if (event === EVENTS.ADD)
10727
10823
  return;
10728
10824
  }
10729
- this._watched.delete(path6);
10825
+ this._watched.delete(path5);
10730
10826
  this._watched.delete(fullPath);
10731
10827
  const eventName = isDirectory ? EVENTS.UNLINK_DIR : EVENTS.UNLINK;
10732
- if (wasTracked && !this._isIgnored(path6))
10733
- this._emit(eventName, path6);
10734
- this._closePath(path6);
10828
+ if (wasTracked && !this._isIgnored(path5))
10829
+ this._emit(eventName, path5);
10830
+ this._closePath(path5);
10735
10831
  }
10736
10832
  /**
10737
10833
  * Closes all watchers for a path
10738
10834
  */
10739
- _closePath(path6) {
10740
- this._closeFile(path6);
10741
- const dir = sp2.dirname(path6);
10742
- this._getWatchedDir(dir).remove(sp2.basename(path6));
10835
+ _closePath(path5) {
10836
+ this._closeFile(path5);
10837
+ const dir = sp2.dirname(path5);
10838
+ this._getWatchedDir(dir).remove(sp2.basename(path5));
10743
10839
  }
10744
10840
  /**
10745
10841
  * Closes only file-specific watchers
10746
10842
  */
10747
- _closeFile(path6) {
10748
- const closers = this._closers.get(path6);
10843
+ _closeFile(path5) {
10844
+ const closers = this._closers.get(path5);
10749
10845
  if (!closers)
10750
10846
  return;
10751
10847
  closers.forEach((closer) => closer());
10752
- this._closers.delete(path6);
10848
+ this._closers.delete(path5);
10753
10849
  }
10754
- _addPathCloser(path6, closer) {
10850
+ _addPathCloser(path5, closer) {
10755
10851
  if (!closer)
10756
10852
  return;
10757
- let list = this._closers.get(path6);
10853
+ let list = this._closers.get(path5);
10758
10854
  if (!list) {
10759
10855
  list = [];
10760
- this._closers.set(path6, list);
10856
+ this._closers.set(path5, list);
10761
10857
  }
10762
10858
  list.push(closer);
10763
10859
  }
@@ -10826,14 +10922,14 @@ function startWatcher(opts) {
10826
10922
  const binding = pathBindings.get(removedPath);
10827
10923
  if (!binding) return;
10828
10924
  try {
10829
- opts.archive.db.insert(ingestionEvents).values({
10925
+ opts.archive.recordIngestionEvent({
10830
10926
  agent: binding.plugin.id,
10831
10927
  sourceId: binding.ref.sourceId,
10832
10928
  sourcePath: removedPath,
10833
10929
  eventType: "unlink_observed",
10834
10930
  detail: { path: removedPath },
10835
10931
  observedAt: /* @__PURE__ */ new Date()
10836
- }).run();
10932
+ });
10837
10933
  } catch (err) {
10838
10934
  onError(err);
10839
10935
  }
@@ -10855,13 +10951,13 @@ function startWatcher(opts) {
10855
10951
  }
10856
10952
  return {
10857
10953
  ready,
10858
- notifyChange(path6) {
10859
- if (watcher2) watcher2.emit("change", path6);
10860
- else scheduleIngest(path6);
10954
+ notifyChange(path5) {
10955
+ if (watcher2) watcher2.emit("change", path5);
10956
+ else scheduleIngest(path5);
10861
10957
  },
10862
- notifyUnlink(path6) {
10863
- if (watcher2) watcher2.emit("unlink", path6);
10864
- else recordUnlink(path6);
10958
+ notifyUnlink(path5) {
10959
+ if (watcher2) watcher2.emit("unlink", path5);
10960
+ else recordUnlink(path5);
10865
10961
  },
10866
10962
  async close() {
10867
10963
  closed = true;
@@ -10873,38 +10969,38 @@ function startWatcher(opts) {
10873
10969
  }
10874
10970
 
10875
10971
  // src/plugins/claude-code/plugin.ts
10876
- import fs6 from "fs";
10877
- import path4 from "path";
10972
+ import fs5 from "fs";
10973
+ import path3 from "path";
10878
10974
  import readline from "readline";
10879
10975
  var ClaudeCodePlugin = class {
10880
10976
  id = "claude-code";
10881
10977
  displayName = "Claude Code";
10882
10978
  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 });
10979
+ const projectsDir = path3.join(env.homeDir, ".claude", "projects");
10980
+ if (!fs5.existsSync(projectsDir)) return;
10981
+ const projects = fs5.readdirSync(projectsDir, { withFileTypes: true });
10886
10982
  for (const project of projects) {
10887
10983
  if (!project.isDirectory()) continue;
10888
- const projectPath = path4.join(projectsDir, project.name);
10889
- const files = fs6.readdirSync(projectPath, { withFileTypes: true });
10984
+ const projectPath = path3.join(projectsDir, project.name);
10985
+ const files = fs5.readdirSync(projectPath, { withFileTypes: true });
10890
10986
  for (const file of files) {
10891
10987
  if (!file.isFile() || !file.name.endsWith(".jsonl")) continue;
10892
- const sourcePath = path4.join(projectPath, file.name);
10988
+ const sourcePath = path3.join(projectPath, file.name);
10893
10989
  const sourceId = file.name.replace(/\.jsonl$/, "");
10894
10990
  const cwd = await readCwdFromJsonl(sourcePath);
10895
10991
  yield {
10896
10992
  sourceId,
10897
10993
  sourcePath,
10898
10994
  watchPaths: [sourcePath],
10899
- project: cwd ? path4.basename(cwd) : void 0,
10995
+ project: cwd ? path3.basename(cwd) : void 0,
10900
10996
  projectPath: cwd ?? void 0
10901
10997
  };
10902
10998
  }
10903
10999
  }
10904
11000
  }
10905
11001
  async *extractRaw(ref) {
10906
- if (!fs6.existsSync(ref.sourcePath)) return;
10907
- const stream = fs6.createReadStream(ref.sourcePath, { encoding: "utf-8" });
11002
+ if (!fs5.existsSync(ref.sourcePath)) return;
11003
+ const stream = fs5.createReadStream(ref.sourcePath, { encoding: "utf-8" });
10908
11004
  const rl = readline.createInterface({ input: stream, crlfDelay: Infinity });
10909
11005
  let lineNo = 0;
10910
11006
  for await (const line of rl) {
@@ -10953,7 +11049,7 @@ var ClaudeCodePlugin = class {
10953
11049
  };
10954
11050
  async function readCwdFromJsonl(sourcePath) {
10955
11051
  try {
10956
- const stream = fs6.createReadStream(sourcePath, { encoding: "utf-8" });
11052
+ const stream = fs5.createReadStream(sourcePath, { encoding: "utf-8" });
10957
11053
  const rl = readline.createInterface({ input: stream, crlfDelay: Infinity });
10958
11054
  try {
10959
11055
  for await (const line of rl) {
@@ -11060,9 +11156,9 @@ Environment:
11060
11156
  `;
11061
11157
 
11062
11158
  // 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"));
11159
+ var __dirname = path4.dirname(fileURLToPath2(import.meta.url));
11160
+ var pkgPath = path4.join(__dirname, "../../package.json");
11161
+ var pkg = JSON.parse(fs6.readFileSync(pkgPath, "utf-8"));
11066
11162
  var action = parseCliArgs(process.argv.slice(2), {
11067
11163
  PORT: process.env.PORT
11068
11164
  });
@@ -11079,8 +11175,8 @@ if (action.kind === "error") {
11079
11175
  process.exit(1);
11080
11176
  }
11081
11177
  updateNotifier({ pkg }).notify({ defer: false, isGlobal: true });
11082
- var dataDir = path5.join(os.homedir(), ".chat-logbook");
11083
- var webDistDir = path5.join(__dirname, "../../web/dist");
11178
+ var dataDir = path4.join(os.homedir(), ".chat-logbook");
11179
+ var webDistDir = path4.join(__dirname, "../../web/dist");
11084
11180
  var port = action.port;
11085
11181
  var archive = createArchiveRepository({ dataDir });
11086
11182
  var checkpoint = createCheckpointRepository({ dataDir });