chatroom-cli 1.98.2 → 1.98.4

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/dist/index.js CHANGED
@@ -110218,7 +110218,8 @@ var init_file_content_fulfillment = __esm(() => {
110218
110218
  return exports_Effect.succeed(Buffer.from("[Error reading file]"));
110219
110219
  });
110220
110220
  if (fileNotFound) {
110221
- console.log(`[${formatTimestamp()}] ⏳ File not on disk yet, deferring content sync: ${filePath}`);
110221
+ yield* fulfillGzippedContentEffect(session2, workingDir, filePath, "[File not found]", false);
110222
+ console.log(`[${formatTimestamp()}] \uD83D\uDCC4 File not found, fulfilled content request: ${filePath}`);
110222
110223
  continue;
110223
110224
  }
110224
110225
  const classification2 = classifyFileContent(filePath, new Uint8Array(buffer));
@@ -110258,49 +110259,6 @@ var init_file_content_subscription = __esm(() => {
110258
110259
  init_daemon_services();
110259
110260
  });
110260
110261
 
110261
- // ../../services/backend/src/domain/workspace-file-tree/types.ts
110262
- var MAX_TREE_JSON_BYTES;
110263
- var init_types2 = __esm(() => {
110264
- MAX_TREE_JSON_BYTES = 900 * 1024;
110265
- });
110266
- // ../../services/backend/src/domain/workspace-file-tree/select-strategy.ts
110267
- function treeJsonByteLength(tree) {
110268
- return Buffer.byteLength(JSON.stringify(tree), "utf8");
110269
- }
110270
- function selectFileTreeSnapshotStrategyId(tree) {
110271
- return treeJsonByteLength(tree) > MAX_TREE_JSON_BYTES ? "sharded" : "blob";
110272
- }
110273
- var init_select_strategy = __esm(() => {
110274
- init_types2();
110275
- });
110276
-
110277
- // ../../services/backend/src/domain/workspace-file-tree/registry.ts
110278
- var init_registry5 = __esm(() => {
110279
- init_select_strategy();
110280
- });
110281
- // ../../services/backend/src/domain/workspace-file-tree/transport/blob-snapshot.ts
110282
- function toLegacyBlobSyncArgs(payload) {
110283
- return { data: payload.data, dataHash: payload.dataHash, scannedAt: payload.scannedAt };
110284
- }
110285
-
110286
- // ../../services/backend/src/domain/workspace-file-tree/transport/sharded-snapshot.ts
110287
- function toLegacyShardBatchItem(shard) {
110288
- return { ...shard };
110289
- }
110290
- function toLegacyManifestSyncArgs(manifest) {
110291
- return { ...manifest };
110292
- }
110293
- // ../../services/backend/src/domain/workspace-file-tree/transport/index.ts
110294
- var init_transport = () => {};
110295
-
110296
- // ../../services/backend/src/domain/workspace-file-tree/index.ts
110297
- var init_workspace_file_tree = __esm(() => {
110298
- init_types2();
110299
- init_select_strategy();
110300
- init_registry5();
110301
- init_transport();
110302
- });
110303
-
110304
110262
  // src/infrastructure/services/workspace/file-tree-data-hash.ts
110305
110263
  import { createHash as createHash6 } from "node:crypto";
110306
110264
  function computeFileTreeDataHash(tree) {
@@ -110308,166 +110266,212 @@ function computeFileTreeDataHash(tree) {
110308
110266
  }
110309
110267
  var init_file_tree_data_hash = () => {};
110310
110268
 
110311
- // src/infrastructure/services/workspace/transport/blob-snapshot-publish.ts
110312
- import { gzipSync as gzipSync2 } from "node:zlib";
110313
- function buildBlobSnapshotPayload(tree, dataHash) {
110314
- const compressed = gzipSync2(Buffer.from(JSON.stringify(tree))).toString("base64");
110315
- return {
110316
- data: { compression: "gzip", content: compressed },
110317
- dataHash,
110318
- scannedAt: tree.scannedAt
110319
- };
110320
- }
110321
- async function publishBlobSnapshot(session2, workingDir, payload) {
110322
- await session2.backend.mutation(api.workspaceFiles.syncFileTreeV2, {
110323
- sessionId: session2.sessionId,
110324
- machineId: session2.machineId,
110325
- workingDir,
110326
- ...toLegacyBlobSyncArgs(payload)
110327
- });
110328
- return {
110329
- strategyId: "blob",
110330
- snapshotId: payload.dataHash,
110331
- scannedAt: payload.scannedAt,
110332
- entryCount: 0
110333
- };
110334
- }
110335
- var init_blob_snapshot_publish = __esm(() => {
110336
- init_api3();
110337
- });
110338
-
110339
- // src/infrastructure/services/workspace/file-tree-partition.ts
110340
- import { createHash as createHash7 } from "node:crypto";
110341
- import { gzipSync as gzipSync3 } from "node:zlib";
110342
- function computeShardDataHash(payload) {
110343
- return createHash7("md5").update(JSON.stringify(payload)).digest("hex");
110344
- }
110345
- function shardIdForPath(path3) {
110346
- const slash = path3.indexOf("/");
110347
- return slash === -1 ? "__root__" : path3.slice(0, slash);
110348
- }
110349
- function childShardId(path3, parentShardId) {
110350
- if (parentShardId === "__root__") {
110351
- return shardIdForPath(path3);
110352
- }
110353
- if (path3 === parentShardId) {
110354
- return parentShardId;
110355
- }
110356
- const prefix = `${parentShardId}/`;
110357
- if (!path3.startsWith(prefix)) {
110358
- return parentShardId;
110359
- }
110360
- const remainder = path3.slice(prefix.length);
110361
- const slash = remainder.indexOf("/");
110362
- return slash === -1 ? parentShardId : `${parentShardId}/${remainder.slice(0, slash)}`;
110363
- }
110364
- function groupEntriesByShardId(entries2, parentShardId) {
110365
- const groups = new Map;
110366
- for (const entry of entries2) {
110367
- const shardId = parentShardId === "__root__" ? shardIdForPath(entry.path) : childShardId(entry.path, parentShardId);
110368
- const group = groups.get(shardId) ?? [];
110369
- group.push(entry);
110370
- groups.set(shardId, group);
110371
- }
110372
- return groups;
110373
- }
110374
- function buildPreparedShard(shardId, payload) {
110375
- const compressed = gzipSync3(Buffer.from(JSON.stringify(payload))).toString("base64");
110376
- return {
110377
- shardId,
110378
- payload,
110379
- dataHash: computeShardDataHash(payload),
110380
- entryCount: payload.entries.length,
110381
- data: { compression: "gzip", content: compressed }
110382
- };
110383
- }
110384
- function subdivideShardGroup(subgroups, tree) {
110385
- const shards = [];
110386
- for (const [subId, subEntries] of subgroups) {
110387
- shards.push(...prepareShardGroup(subEntries, subId, tree));
110388
- }
110389
- return shards;
110390
- }
110391
- function shouldSkipParentCompression(subgroups, entryCount) {
110392
- return subgroups.size > 1 && entryCount > LARGE_SHARD_ENTRY_THRESHOLD;
110393
- }
110394
- function prepareShardGroup(entries2, shardId, tree) {
110395
- const subgroups = groupEntriesByShardId(entries2, shardId);
110396
- if (shouldSkipParentCompression(subgroups, entries2.length)) {
110397
- return subdivideShardGroup(subgroups, tree);
110398
- }
110399
- const payload = {
110400
- entries: entries2,
110401
- scannedAt: tree.scannedAt,
110402
- rootDir: tree.rootDir
110403
- };
110404
- const compressed = gzipSync3(Buffer.from(JSON.stringify(payload))).toString("base64");
110405
- if (Buffer.byteLength(compressed, "utf8") <= MAX_SHARD_JSON_BYTES || subgroups.size <= 1) {
110406
- return [buildPreparedShard(shardId, payload)];
110407
- }
110408
- return subdivideShardGroup(subgroups, tree);
110409
- }
110410
- function partitionFileTree(tree) {
110411
- const topGroups = groupEntriesByShardId(tree.entries, "__root__");
110412
- const shards = [];
110413
- for (const [shardId, entries2] of topGroups) {
110414
- shards.push(...prepareShardGroup(entries2, shardId, tree));
110415
- }
110416
- return shards;
110417
- }
110418
- var MAX_TREE_JSON_BYTES2, MAX_SHARD_JSON_BYTES, MAX_SHARD_BATCH_SIZE = 8, LARGE_SHARD_ENTRY_THRESHOLD = 50000;
110419
- var init_file_tree_partition = __esm(() => {
110420
- init_workspace_file_tree();
110421
- MAX_TREE_JSON_BYTES2 = 900 * 1024;
110422
- MAX_SHARD_JSON_BYTES = 800 * 1024;
110423
- });
110424
-
110425
- // src/infrastructure/services/workspace/transport/sharded-snapshot-publish.ts
110426
- async function publishShardedSnapshot(session2, workingDir, tree, syncGeneration) {
110427
- const shards = partitionFileTree(tree);
110428
- const shardIds = [];
110429
- for (let i2 = 0;i2 < shards.length; i2 += MAX_SHARD_BATCH_SIZE) {
110430
- const batch = shards.slice(i2, i2 + MAX_SHARD_BATCH_SIZE);
110431
- const items = batch.map((s) => ({
110432
- shardId: s.shardId,
110433
- data: s.data,
110434
- dataHash: s.dataHash,
110435
- scannedAt: tree.scannedAt,
110436
- entryCount: s.entryCount
110437
- }));
110438
- await session2.backend.mutation(api.workspaceFiles.syncFileTreeShardV3Batch, {
110439
- sessionId: session2.sessionId,
110440
- machineId: session2.machineId,
110441
- workingDir,
110442
- syncGeneration,
110443
- items: items.map(toLegacyShardBatchItem)
110444
- });
110445
- for (const s of batch)
110446
- shardIds.push(s.shardId);
110447
- }
110448
- const manifest = {
110449
- syncGeneration,
110450
- shardIds,
110451
- totalEntryCount: tree.entries.length,
110452
- complete: true,
110453
- scannedAt: tree.scannedAt
110454
- };
110455
- await session2.backend.mutation(api.workspaceFiles.syncFileTreeManifestV3, {
110456
- sessionId: session2.sessionId,
110457
- machineId: session2.machineId,
110458
- workingDir,
110459
- ...toLegacyManifestSyncArgs(manifest)
110460
- });
110461
- return {
110462
- strategyId: "sharded",
110463
- snapshotId: syncGeneration,
110464
- scannedAt: tree.scannedAt,
110465
- entryCount: tree.entries.length
110466
- };
110467
- }
110468
- var init_sharded_snapshot_publish = __esm(() => {
110469
- init_api3();
110470
- init_file_tree_partition();
110269
+ // src/infrastructure/services/workspace/file-tree-sync-ranker.ts
110270
+ function fileExtension(p) {
110271
+ const b = (p.split("/").pop() ?? p).toLowerCase();
110272
+ if (b.endsWith(".min.js"))
110273
+ return ".min.js";
110274
+ if (b.endsWith(".min.css"))
110275
+ return ".min.css";
110276
+ const i2 = b.lastIndexOf(".");
110277
+ return i2 <= 0 ? "" : b.slice(i2);
110278
+ }
110279
+ function pathSegments(p) {
110280
+ return p.split("/").filter(Boolean);
110281
+ }
110282
+ function parentDir(p) {
110283
+ const i2 = p.lastIndexOf("/");
110284
+ return i2 < 0 ? "" : p.slice(0, i2);
110285
+ }
110286
+ function isSourceDirPath(p) {
110287
+ return pathSegments(p).slice(0, -1).some((s) => SOURCE_DIR_NAMES.has(s));
110288
+ }
110289
+ function isBuildDirPath(p) {
110290
+ return pathSegments(p).some((s) => BUILD_DIR_NAMES.has(s));
110291
+ }
110292
+ function isMarkdownFile(p) {
110293
+ return MARKDOWN_EXTENSIONS.has(fileExtension(p));
110294
+ }
110295
+ function isConfigFile(p) {
110296
+ return CONFIG_BASENAMES.has((p.split("/").pop() ?? "").toLowerCase()) || CONFIG_EXTENSIONS.has(fileExtension(p));
110297
+ }
110298
+ function isSourceFile(p) {
110299
+ return SOURCE_EXTENSIONS.has(fileExtension(p));
110300
+ }
110301
+ function isBuildOutputFile(p) {
110302
+ return BUILD_OUTPUT_EXTENSIONS.has(fileExtension(p));
110303
+ }
110304
+ function isDataFile(p) {
110305
+ return !isConfigFile(p) && DATA_EXTENSIONS.has(fileExtension(p));
110306
+ }
110307
+ function countDataFilesByParent(ps) {
110308
+ const m = new Map;
110309
+ for (const p of ps)
110310
+ if (isDataFile(p)) {
110311
+ const d = parentDir(p);
110312
+ m.set(d, (m.get(d) ?? 0) + 1);
110313
+ }
110314
+ return m;
110315
+ }
110316
+ function scoreFile(p, m) {
110317
+ let s = 0;
110318
+ if (isSourceFile(p))
110319
+ s += isSourceDirPath(p) ? SCORE_SOURCE_IN_SOURCE_DIR : SCORE_SOURCE_ELSEWHERE;
110320
+ if (isMarkdownFile(p))
110321
+ s += SCORE_MARKDOWN;
110322
+ if (isConfigFile(p))
110323
+ s += SCORE_CONFIG;
110324
+ if (isBuildDirPath(p))
110325
+ s -= PENALTY_BUILD_DIR;
110326
+ if (isBuildOutputFile(p))
110327
+ s -= PENALTY_BUILD_EXT;
110328
+ const n = m.get(parentDir(p)) ?? 0;
110329
+ return s - n * n;
110330
+ }
110331
+ function compareRankedFiles(a, as7, b, bs) {
110332
+ if (as7 !== bs)
110333
+ return bs - as7;
110334
+ const d = pathSegments(a).length - pathSegments(b).length;
110335
+ return d || a.localeCompare(b);
110336
+ }
110337
+ var SOURCE_DIR_NAMES, BUILD_DIR_NAMES, SOURCE_EXTENSIONS, MARKDOWN_EXTENSIONS, CONFIG_EXTENSIONS, CONFIG_BASENAMES, BUILD_OUTPUT_EXTENSIONS, DATA_EXTENSIONS, SCORE_SOURCE_IN_SOURCE_DIR = 1000, SCORE_MARKDOWN = 800, SCORE_CONFIG = 700, SCORE_SOURCE_ELSEWHERE = 200, PENALTY_BUILD_DIR = 5000, PENALTY_BUILD_EXT = 2000;
110338
+ var init_file_tree_sync_ranker = __esm(() => {
110339
+ SOURCE_DIR_NAMES = new Set([
110340
+ "src",
110341
+ "lib",
110342
+ "app",
110343
+ "apps",
110344
+ "packages",
110345
+ "services",
110346
+ "server",
110347
+ "client",
110348
+ "backend",
110349
+ "frontend",
110350
+ "api",
110351
+ "cmd",
110352
+ "internal",
110353
+ "pkg",
110354
+ "components",
110355
+ "modules",
110356
+ "pages",
110357
+ "routes",
110358
+ "hooks",
110359
+ "domain",
110360
+ "infrastructure",
110361
+ "entry"
110362
+ ]);
110363
+ BUILD_DIR_NAMES = new Set([
110364
+ "dist",
110365
+ "build",
110366
+ "out",
110367
+ "output",
110368
+ "coverage",
110369
+ ".next",
110370
+ ".turbo",
110371
+ ".nx",
110372
+ "_generated",
110373
+ "generated",
110374
+ "__pycache__"
110375
+ ]);
110376
+ SOURCE_EXTENSIONS = new Set([
110377
+ ".ts",
110378
+ ".tsx",
110379
+ ".js",
110380
+ ".jsx",
110381
+ ".mjs",
110382
+ ".cjs",
110383
+ ".py",
110384
+ ".go",
110385
+ ".rs",
110386
+ ".java",
110387
+ ".kt",
110388
+ ".swift",
110389
+ ".rb",
110390
+ ".php",
110391
+ ".cs",
110392
+ ".c",
110393
+ ".cc",
110394
+ ".cpp",
110395
+ ".h",
110396
+ ".hpp",
110397
+ ".vue",
110398
+ ".svelte",
110399
+ ".css",
110400
+ ".scss",
110401
+ ".less"
110402
+ ]);
110403
+ MARKDOWN_EXTENSIONS = new Set([".md", ".mdx", ".markdown"]);
110404
+ CONFIG_EXTENSIONS = new Set([".yml", ".yaml", ".toml", ".jsonc", ".ini", ".cfg"]);
110405
+ CONFIG_BASENAMES = new Set([
110406
+ "package.json",
110407
+ "package-lock.json",
110408
+ "pnpm-lock.yaml",
110409
+ "pnpm-workspace.yaml",
110410
+ "yarn.lock",
110411
+ "bun.lock",
110412
+ "tsconfig.json",
110413
+ "jsconfig.json",
110414
+ "turbo.json",
110415
+ "nx.json",
110416
+ "cargo.toml",
110417
+ "go.mod",
110418
+ "go.sum",
110419
+ "pyproject.toml",
110420
+ "requirements.txt",
110421
+ "dockerfile",
110422
+ "docker-compose.yml",
110423
+ "docker-compose.yaml",
110424
+ "makefile",
110425
+ ".gitignore",
110426
+ ".cursorignore",
110427
+ ".editorconfig",
110428
+ ".prettierrc",
110429
+ ".nvmrc",
110430
+ "eslint.config.mjs",
110431
+ "eslint.config.js",
110432
+ "biome.json",
110433
+ ".fallowrc.jsonc"
110434
+ ]);
110435
+ BUILD_OUTPUT_EXTENSIONS = new Set([
110436
+ ".map",
110437
+ ".min.js",
110438
+ ".min.css",
110439
+ ".pyc",
110440
+ ".pyo",
110441
+ ".o",
110442
+ ".obj",
110443
+ ".wasm",
110444
+ ".class",
110445
+ ".jar",
110446
+ ".exe",
110447
+ ".dll",
110448
+ ".so"
110449
+ ]);
110450
+ DATA_EXTENSIONS = new Set([
110451
+ ".json",
110452
+ ".csv",
110453
+ ".tsv",
110454
+ ".ndjson",
110455
+ ".parquet",
110456
+ ".avro",
110457
+ ".bin",
110458
+ ".dat",
110459
+ ".pb",
110460
+ ".sqlite",
110461
+ ".db",
110462
+ ".log",
110463
+ ".gz",
110464
+ ".zip",
110465
+ ".tar",
110466
+ ".png",
110467
+ ".jpg",
110468
+ ".jpeg",
110469
+ ".webp",
110470
+ ".gif",
110471
+ ".mp4",
110472
+ ".woff",
110473
+ ".woff2"
110474
+ ]);
110471
110475
  });
110472
110476
 
110473
110477
  // ../../node_modules/.pnpm/ignore@7.0.5/node_modules/ignore/index.js
@@ -110800,10 +110804,68 @@ var require_ignore = __commonJS((exports, module) => {
110800
110804
  // src/infrastructure/services/workspace/workspace-ignore.ts
110801
110805
  import { promises as fsPromises } from "node:fs";
110802
110806
  import { readFile as readFile10 } from "node:fs/promises";
110807
+ import { homedir as homedir7 } from "node:os";
110803
110808
  import path3 from "node:path";
110804
110809
  function normalizeRelativePath(relativePath) {
110805
110810
  return relativePath.replace(/\\/g, "/").replace(/^\.?\//, "").replace(/\/+$/, "");
110806
110811
  }
110812
+ function expandUserPath(filePath) {
110813
+ if (filePath === "~")
110814
+ return homedir7();
110815
+ if (filePath.startsWith("~/"))
110816
+ return path3.join(homedir7(), filePath.slice(2));
110817
+ return filePath;
110818
+ }
110819
+ function readExcludesFileFromGitconfig(content) {
110820
+ let inCore = false;
110821
+ for (const line of content.split(/\r?\n/)) {
110822
+ const section = line.match(/^\s*\[([^\]]+)\]/);
110823
+ if (section) {
110824
+ inCore = section[1].trim().toLowerCase() === "core";
110825
+ continue;
110826
+ }
110827
+ if (!inCore)
110828
+ continue;
110829
+ const match17 = line.match(/^\s*excludesfile\s*=\s*(.*?)\s*(?:[#;].*)?$/i);
110830
+ if (!match17)
110831
+ continue;
110832
+ const value = match17[1].trim().replace(/^(["'])(.*)\1$/, "$2");
110833
+ return value ? expandUserPath(value) : null;
110834
+ }
110835
+ return null;
110836
+ }
110837
+ async function readGitconfigExcludesFilePath(configPath) {
110838
+ const content = await readIgnoreFile(configPath);
110839
+ if (content === null)
110840
+ return null;
110841
+ const raw = readExcludesFileFromGitconfig(content);
110842
+ if (!raw)
110843
+ return null;
110844
+ return path3.isAbsolute(raw) ? expandUserPath(raw) : path3.resolve(path3.dirname(configPath), raw);
110845
+ }
110846
+ async function resolveGitExtraExcludeFilePaths(rootDir) {
110847
+ const globalConfig2 = process.env.GIT_CONFIG_GLOBAL?.length ? process.env.GIT_CONFIG_GLOBAL : path3.join(homedir7(), ".gitconfig");
110848
+ const localConfig = path3.join(rootDir, ".git", "config");
110849
+ let excludesFile = await readGitconfigExcludesFilePath(localConfig) ?? await readGitconfigExcludesFilePath(globalConfig2);
110850
+ if (!excludesFile) {
110851
+ excludesFile = path3.join(process.env.XDG_CONFIG_HOME?.length ? process.env.XDG_CONFIG_HOME : path3.join(homedir7(), ".config"), "git", "ignore");
110852
+ }
110853
+ const candidates = [excludesFile, path3.join(rootDir, ".git", "info", "exclude")];
110854
+ const existing = [];
110855
+ for (const candidate of candidates)
110856
+ if (await readIgnoreFile(candidate) !== null)
110857
+ existing.push(candidate);
110858
+ return existing;
110859
+ }
110860
+ async function loadGitExtraExcludeRuleSets(rootDir) {
110861
+ const result = [];
110862
+ for (const filePath of await resolveGitExtraExcludeFilePaths(rootDir)) {
110863
+ const content = await readIgnoreFile(filePath);
110864
+ if (content !== null)
110865
+ result.push({ baseDir: "", matcher: import_ignore.default().add(content) });
110866
+ }
110867
+ return result;
110868
+ }
110807
110869
  async function readIgnoreFile(filePath) {
110808
110870
  try {
110809
110871
  return await readFile10(filePath, "utf-8");
@@ -110815,7 +110877,7 @@ async function loadDirectoryIgnoreRuleSets(rootDir, relativeDir) {
110815
110877
  const normalizedDir = normalizeRelativePath(relativeDir);
110816
110878
  const absoluteDir = normalizedDir ? path3.join(rootDir, normalizedDir) : rootDir;
110817
110879
  const names = normalizedDir ? [".gitignore"] : IGNORE_FILES;
110818
- const result = [];
110880
+ const result = normalizedDir ? [] : await loadGitExtraExcludeRuleSets(rootDir);
110819
110881
  for (const name of names) {
110820
110882
  const content = await readIgnoreFile(path3.join(absoluteDir, name));
110821
110883
  if (content === null)
@@ -110912,48 +110974,57 @@ async function walkWorkspaceFiles(rootDir, options) {
110912
110974
  const filePaths = [];
110913
110975
  const directoryStubs = [];
110914
110976
  let truncated = false;
110915
- async function visitDir(relDir, inheritedRuleSets, siblingCount) {
110916
- if (truncated || filePaths.length >= maxFilePaths) {
110977
+ let currentLevel = [{ relDir: "", inheritedRuleSets: [], siblingCount: 0 }];
110978
+ while (currentLevel.length > 0) {
110979
+ if (filePaths.length >= maxFilePaths) {
110917
110980
  truncated = true;
110918
- return;
110981
+ break;
110919
110982
  }
110920
- const localRuleSets = await loadDirectoryIgnoreRuleSets(rootDir, relDir);
110921
- const ruleSets = mergeWorkspaceIgnoreRuleSets(inheritedRuleSets, localRuleSets);
110922
- const dirents = await readWorkspaceDirectoryDirents(rootDir, relDir);
110923
- if (!dirents)
110924
- return;
110925
- for (const ent of dirents) {
110926
- if (truncated || filePaths.length >= maxFilePaths) {
110983
+ const nextLevel = [];
110984
+ for (const frame of currentLevel) {
110985
+ if (filePaths.length >= maxFilePaths) {
110927
110986
  truncated = true;
110928
- return;
110987
+ break;
110929
110988
  }
110930
- const relativePath = relDir ? `${relDir}/${ent.name}` : ent.name;
110931
- if (!isPathVisible(relativePath))
110989
+ const localRuleSets = await loadDirectoryIgnoreRuleSets(rootDir, frame.relDir);
110990
+ const ruleSets = mergeWorkspaceIgnoreRuleSets(frame.inheritedRuleSets, localRuleSets);
110991
+ const dirents = await readWorkspaceDirectoryDirents(rootDir, frame.relDir);
110992
+ if (!dirents)
110932
110993
  continue;
110933
- if (ent.isDirectory()) {
110934
- if (isPathIgnoredByRuleSets(ruleSets, relativePath))
110935
- continue;
110936
- const syncMode = classifyDirectorySyncMode(ent.name, {
110937
- relativePath,
110938
- immediateSiblingCount: siblingCount,
110939
- immediateChildCount: dirents.length
110940
- });
110941
- if (syncMode === "hidden")
110994
+ for (const ent of dirents) {
110995
+ const relativePath = frame.relDir ? `${frame.relDir}/${ent.name}` : ent.name;
110996
+ if (!isPathVisible(relativePath))
110942
110997
  continue;
110943
- directoryStubs.push(relativePath);
110944
- if (syncMode === "shallow")
110945
- continue;
110946
- await visitDir(relativePath, ruleSets, dirents.length);
110947
- } else if (ent.isFile()) {
110948
- if (isPathIgnoredByRuleSets(ruleSets, relativePath))
110949
- continue;
110950
- filePaths.push(relativePath);
110951
- if (filePaths.length >= maxFilePaths)
110952
- truncated = true;
110998
+ if (ent.isDirectory()) {
110999
+ if (isPathIgnoredByRuleSets(ruleSets, relativePath))
111000
+ continue;
111001
+ const syncMode = classifyDirectorySyncMode(ent.name, {
111002
+ relativePath,
111003
+ immediateSiblingCount: frame.siblingCount,
111004
+ immediateChildCount: dirents.length
111005
+ });
111006
+ if (syncMode === "hidden")
111007
+ continue;
111008
+ directoryStubs.push(relativePath);
111009
+ if (syncMode === "full")
111010
+ nextLevel.push({
111011
+ relDir: relativePath,
111012
+ inheritedRuleSets: ruleSets,
111013
+ siblingCount: dirents.length
111014
+ });
111015
+ } else if (ent.isFile() && !isPathIgnoredByRuleSets(ruleSets, relativePath)) {
111016
+ if (filePaths.length >= maxFilePaths) {
111017
+ truncated = true;
111018
+ continue;
111019
+ }
111020
+ filePaths.push(relativePath);
111021
+ if (filePaths.length >= maxFilePaths)
111022
+ truncated = true;
111023
+ }
110953
111024
  }
110954
111025
  }
111026
+ currentLevel = truncated ? [] : nextLevel;
110955
111027
  }
110956
- await visitDir("", [], 0);
110957
111028
  return { filePaths, directoryStubs, truncated };
110958
111029
  }
110959
111030
  var init_workspace_file_walk = __esm(() => {
@@ -110965,7 +111036,7 @@ var init_workspace_file_walk = __esm(() => {
110965
111036
  async function scanFileTree(rootDir, options) {
110966
111037
  const maxEntries = options?.maxEntries ?? DEFAULT_MAX_ENTRIES;
110967
111038
  const scannedAt = Date.now();
110968
- const walk = await walkWorkspaceFiles(rootDir, { maxFilePaths: maxEntries });
111039
+ const walk = await walkWorkspaceFiles(rootDir, { maxFilePaths: DEFAULT_CANDIDATE_FILE_PATHS });
110969
111040
  const filteredPaths = walk.filePaths.filter((p) => !isExcluded(p));
110970
111041
  const filteredStubs = walk.directoryStubs.filter((p) => !isExcluded(p));
110971
111042
  const entries2 = buildEntries(filteredPaths, filteredStubs, maxEntries);
@@ -110982,30 +111053,35 @@ function entryDepth(entryPath) {
110982
111053
  return entryPath.split("/").length;
110983
111054
  }
110984
111055
  function buildEntries(filePaths, directoryStubs, maxEntries) {
110985
- const directories = new Set(directoryStubs);
110986
- for (const filePath of filePaths) {
110987
- const parts2 = filePath.split("/");
110988
- for (let i2 = 1;i2 < parts2.length; i2++) {
110989
- directories.add(parts2.slice(0, i2).join("/"));
110990
- }
111056
+ const selected = new Map;
111057
+ const data = countDataFilesByParent(filePaths);
111058
+ const ranked = [...filePaths].sort((a, b) => compareRankedFiles(a, scoreFile(a, data), b, scoreFile(b, data)));
111059
+ for (const file2 of ranked) {
111060
+ const parts2 = file2.split("/");
111061
+ const needed = [file2, ...parts2.slice(0, -1).map((_, i2) => parts2.slice(0, i2 + 1).join("/"))];
111062
+ const missing = needed.filter((p) => !selected.has(p));
111063
+ if (selected.size + missing.length > maxEntries)
111064
+ continue;
111065
+ for (const p of needed)
111066
+ selected.set(p, { path: p, type: p === file2 ? "file" : "directory" });
110991
111067
  }
110992
- const entries2 = [
110993
- ...Array.from(directories).map((dir) => ({ path: dir, type: "directory" })),
110994
- ...filePaths.map((file2) => ({ path: file2, type: "file" }))
110995
- ];
110996
- const uniqueByPath = new Map;
110997
- for (const entry of entries2) {
110998
- uniqueByPath.set(entry.path, entry);
111068
+ for (const dir of [...directoryStubs].sort((a, b) => entryDepth(a) - entryDepth(b) || a.localeCompare(b))) {
111069
+ if (selected.has(dir))
111070
+ continue;
111071
+ if (selected.size >= maxEntries)
111072
+ break;
111073
+ selected.set(dir, { path: dir, type: "directory" });
110999
111074
  }
111000
- return Array.from(uniqueByPath.values()).sort((left3, right3) => {
111075
+ return Array.from(selected.values()).sort((left3, right3) => {
111001
111076
  const depthDelta = entryDepth(left3.path) - entryDepth(right3.path);
111002
111077
  if (depthDelta !== 0)
111003
111078
  return depthDelta;
111004
111079
  return left3.path.localeCompare(right3.path);
111005
- }).slice(0, maxEntries);
111080
+ });
111006
111081
  }
111007
- var DEFAULT_MAX_ENTRIES = 1e4;
111082
+ var DEFAULT_MAX_ENTRIES = 1e4, DEFAULT_CANDIDATE_FILE_PATHS = 50000;
111008
111083
  var init_file_tree_scanner = __esm(() => {
111084
+ init_file_tree_sync_ranker();
111009
111085
  init_workspace_file_walk();
111010
111086
  init_workspace_visibility_policy();
111011
111087
  });
@@ -112041,12 +112117,12 @@ class NodeFsHandler {
112041
112117
  });
112042
112118
  }
112043
112119
  async _handleDir(dir, stats, initialAdd, depth, target, wh, realpath3) {
112044
- const parentDir = this.fsw._getWatchedDir(sp.dirname(dir));
112045
- const tracked = parentDir.has(sp.basename(dir));
112120
+ const parentDir2 = this.fsw._getWatchedDir(sp.dirname(dir));
112121
+ const tracked = parentDir2.has(sp.basename(dir));
112046
112122
  if (!(initialAdd && this.fsw.options.ignoreInitial) && !target && !tracked) {
112047
112123
  this.fsw._emit(EV.ADD_DIR, dir, stats);
112048
112124
  }
112049
- parentDir.add(sp.basename(dir));
112125
+ parentDir2.add(sp.basename(dir));
112050
112126
  this.fsw._getWatchedDir(dir);
112051
112127
  let throttler;
112052
112128
  let closer;
@@ -113317,13 +113393,13 @@ function diffPathIndexes(previous, next4) {
113317
113393
  }
113318
113394
 
113319
113395
  // src/infrastructure/services/workspace/workspace-sync-state.ts
113320
- import { createHash as createHash8, randomUUID as randomUUID9 } from "node:crypto";
113396
+ import { createHash as createHash7, randomUUID as randomUUID9 } from "node:crypto";
113321
113397
  import * as fs11 from "node:fs/promises";
113322
- import { homedir as homedir7 } from "node:os";
113398
+ import { homedir as homedir8 } from "node:os";
113323
113399
  import { join as join24 } from "node:path";
113324
113400
  function workspaceKeyFor(workingDir) {
113325
113401
  const normalized = normalizeWorkingDirForLookup(workingDir);
113326
- return createHash8("sha256").update(normalized).digest("hex").slice(0, 16);
113402
+ return createHash7("sha256").update(normalized).digest("hex").slice(0, 16);
113327
113403
  }
113328
113404
  function buildPathIndex(entries2) {
113329
113405
  const paths = {};
@@ -113397,7 +113473,7 @@ function entriesFromPathIndex(paths) {
113397
113473
  }
113398
113474
  var SYNC_STATE_VERSION = "2", SYNC_STATE_DIR;
113399
113475
  var init_workspace_sync_state = __esm(() => {
113400
- SYNC_STATE_DIR = join24(homedir7(), ".chatroom", "sync-state");
113476
+ SYNC_STATE_DIR = join24(homedir8(), ".chatroom", "sync-state");
113401
113477
  });
113402
113478
 
113403
113479
  // src/infrastructure/services/workspace/workspace-file-tree-coordinator.ts
@@ -113547,11 +113623,6 @@ async function startWorkspaceFileTreeCoordinator(options) {
113547
113623
  if (!delta)
113548
113624
  break;
113549
113625
  const result = await options.onDelta(delta, manifest.backendRevision);
113550
- if (result.status === "conflict") {
113551
- manifest.backendRevision = result.revision;
113552
- await saveWorkspaceSyncManifest(manifest);
113553
- continue;
113554
- }
113555
113626
  manifest.backendRevision = result.revision;
113556
113627
  manifest.pendingDeltas.shift();
113557
113628
  await saveWorkspaceSyncManifest(manifest);
@@ -113644,137 +113715,899 @@ async function startWorkspaceFileTreeCoordinator(options) {
113644
113715
  await active2.stop();
113645
113716
  const fs12 = createWorkspaceFsWatcher({
113646
113717
  workingDir,
113647
- shouldIgnore: shouldIgnorePath,
113648
- onEvents: handleChangeSourceEvents,
113649
- onError: handleChangeSourceError
113718
+ shouldIgnore: shouldIgnorePath,
113719
+ onEvents: handleChangeSourceEvents,
113720
+ onError: handleChangeSourceError
113721
+ });
113722
+ changeSource = fs12;
113723
+ await fs12.ready;
113724
+ console.log("[workspace-file-tree] change source: fs (degraded from git)");
113725
+ };
113726
+ const change = await createWorkspaceChangeSource({
113727
+ workingDir,
113728
+ pollIntervalMs: options.changeSourcePollIntervalMs,
113729
+ shouldIgnore: shouldIgnorePath,
113730
+ getKnownPaths: () => manifest.paths,
113731
+ onEvents: handleChangeSourceEvents,
113732
+ onNeedsReconcile: () => enqueueSerial(reconcileNow),
113733
+ onError: handleChangeSourceError,
113734
+ onPersistentFailure: () => degradeGitToFs("persistent git poll failures")
113735
+ });
113736
+ changeSource = change.source;
113737
+ changeSourceMode = change.mode;
113738
+ if (change.mode === "git") {
113739
+ console.log(`[workspace-file-tree] change source: git (${change.gitRepoCount ?? 1} repo${(change.gitRepoCount ?? 1) === 1 ? "" : "s"})`);
113740
+ } else {
113741
+ console.log("[workspace-file-tree] change source: fs");
113742
+ }
113743
+ await changeSource.ready;
113744
+ scheduleReconcile();
113745
+ return {
113746
+ workingDir,
113747
+ getManifest: () => manifest,
113748
+ getTree: () => treeFromManifest(manifest),
113749
+ checkpoint: () => enqueueSerial(publishCheckpoint),
113750
+ reconcile: () => enqueueSerial(reconcileNow),
113751
+ stop: async () => {
113752
+ stopped = true;
113753
+ if (reconcileTimer)
113754
+ clearTimeout(reconcileTimer);
113755
+ reconcileTimer = null;
113756
+ await changeSource?.stop();
113757
+ changeSource = null;
113758
+ await serial;
113759
+ await saveWorkspaceSyncManifest(manifest);
113760
+ }
113761
+ };
113762
+ }
113763
+ var DEFAULT_RECONCILE_INTERVAL_MS, DEFAULT_CHECKPOINT_EVERY_REVISIONS = 100, RECONCILE_JITTER_RATIO = 0.2, MAX_DELTA_OPERATIONS = 100;
113764
+ var init_workspace_file_tree_coordinator = __esm(() => {
113765
+ init_file_tree_data_hash();
113766
+ init_file_tree_scanner();
113767
+ init_git_workspace_porcelain();
113768
+ init_workspace_change_source();
113769
+ init_workspace_fs_watcher();
113770
+ init_workspace_ignore();
113771
+ init_workspace_sync_state();
113772
+ DEFAULT_RECONCILE_INTERVAL_MS = 10 * 60 * 1000;
113773
+ });
113774
+
113775
+ // src/infrastructure/services/workspace/workspace-sync-config.ts
113776
+ var FILE_TREE_SYNC_DEBOUNCE_MS = 5000;
113777
+
113778
+ // src/infrastructure/services/workspace/workspace-sync-queue.ts
113779
+ function queueKey(machineId, workingDir) {
113780
+ return `${machineId}\x00${workingDir}`;
113781
+ }
113782
+ function getOrCreateState(key) {
113783
+ let state = queues.get(key);
113784
+ if (!state) {
113785
+ state = { drainPromise: null, pendingTask: null, scheduled: false };
113786
+ queues.set(key, state);
113787
+ }
113788
+ return state;
113789
+ }
113790
+ function sleep7(ms) {
113791
+ return new Promise((resolve8) => setTimeout(resolve8, ms));
113792
+ }
113793
+ async function drainQueue(state, key, debounceMs) {
113794
+ try {
113795
+ while (state.pendingTask) {
113796
+ const lastCompletedAt = lastCompletedAtByKey.get(key) ?? 0;
113797
+ const elapsed3 = Date.now() - lastCompletedAt;
113798
+ const waitMs = lastCompletedAt === 0 ? 0 : Math.max(0, debounceMs - elapsed3);
113799
+ if (waitMs > 0) {
113800
+ await sleep7(waitMs);
113801
+ }
113802
+ const task = state.pendingTask;
113803
+ if (!task)
113804
+ break;
113805
+ state.pendingTask = null;
113806
+ await task();
113807
+ lastCompletedAtByKey.set(key, Date.now());
113808
+ }
113809
+ } finally {
113810
+ state.drainPromise = null;
113811
+ state.scheduled = false;
113812
+ if (state.pendingTask) {
113813
+ kickDrain(state, key, debounceMs);
113814
+ } else {
113815
+ queues.delete(key);
113816
+ }
113817
+ }
113818
+ }
113819
+ function kickDrain(state, key, debounceMs) {
113820
+ if (state.scheduled || state.drainPromise)
113821
+ return;
113822
+ state.scheduled = true;
113823
+ state.drainPromise = new Promise((resolve8, reject) => {
113824
+ queueMicrotask(() => {
113825
+ drainQueue(state, key, debounceMs).then(resolve8, reject);
113826
+ });
113827
+ });
113828
+ }
113829
+ async function enqueueFileTreeSync(machineId, workingDir, task, options) {
113830
+ const debounceMs = options?.debounceMs ?? FILE_TREE_SYNC_DEBOUNCE_MS;
113831
+ const key = queueKey(machineId, workingDir);
113832
+ const state = getOrCreateState(key);
113833
+ state.pendingTask = task;
113834
+ kickDrain(state, key, debounceMs);
113835
+ return state.drainPromise ?? Promise.resolve();
113836
+ }
113837
+ var queues, lastCompletedAtByKey;
113838
+ var init_workspace_sync_queue = __esm(() => {
113839
+ queues = new Map;
113840
+ lastCompletedAtByKey = new Map;
113841
+ });
113842
+
113843
+ // src/daemon/infrastructure/outbox/lib/durable-coalescing-state-schema.ts
113844
+ var DURABLE_COALESCING_STATE_MIGRATIONS;
113845
+ var init_durable_coalescing_state_schema = __esm(() => {
113846
+ DURABLE_COALESCING_STATE_MIGRATIONS = [
113847
+ `CREATE TABLE IF NOT EXISTS schema_meta (key TEXT PRIMARY KEY, value TEXT NOT NULL)`,
113848
+ `CREATE TABLE IF NOT EXISTS coalescing_outbox_entries (delivery_key TEXT PRIMARY KEY, payload_json TEXT NOT NULL, status TEXT NOT NULL DEFAULT 'pending', attempts INTEGER NOT NULL DEFAULT 0, last_error TEXT, created_at INTEGER NOT NULL, updated_at INTEGER NOT NULL)`
113849
+ ];
113850
+ });
113851
+
113852
+ // src/daemon/infrastructure/outbox/lib/durable-coalescing-state-store.ts
113853
+ import { mkdirSync as mkdirSync6 } from "node:fs";
113854
+ import { dirname as dirname12 } from "node:path";
113855
+ import { DatabaseSync } from "node:sqlite";
113856
+ function openDurableCoalescingStateStore(path8) {
113857
+ mkdirSync6(dirname12(path8), { recursive: true });
113858
+ const db = new DatabaseSync(path8);
113859
+ for (const sql of DURABLE_COALESCING_STATE_MIGRATIONS)
113860
+ db.exec(sql);
113861
+ db.prepare("UPDATE coalescing_outbox_entries SET status='pending' WHERE status='in_flight'").run();
113862
+ return { upsertPending: (key, payload) => {
113863
+ const now = Date.now();
113864
+ db.prepare("INSERT INTO coalescing_outbox_entries(delivery_key,payload_json,status,created_at,updated_at) VALUES(?,?,'pending',?,?) ON CONFLICT(delivery_key) DO UPDATE SET payload_json=excluded.payload_json,status='pending',updated_at=excluded.updated_at").run(key, payload, now, now);
113865
+ }, getPending: (key) => db.prepare("SELECT payload_json as payloadJson, attempts FROM coalescing_outbox_entries WHERE delivery_key=? AND status IN ('pending','in_flight')").get(key) ?? null, markDone: (key) => {
113866
+ db.prepare("DELETE FROM coalescing_outbox_entries WHERE delivery_key=?").run(key);
113867
+ }, markPendingRetry: (key, error51) => {
113868
+ db.prepare("UPDATE coalescing_outbox_entries SET status='pending',last_error=?,attempts=attempts+1,updated_at=? WHERE delivery_key=?").run(String(error51), Date.now(), key);
113869
+ }, listPendingKeys: () => db.prepare("SELECT delivery_key as key FROM coalescing_outbox_entries WHERE status IN ('pending','in_flight')").all().map((r) => String(r.key)), close: () => db.close() };
113870
+ }
113871
+ var init_durable_coalescing_state_store = __esm(() => {
113872
+ init_durable_coalescing_state_schema();
113873
+ });
113874
+
113875
+ // src/daemon/infrastructure/outbox/lib/outbox-retry-backoff.ts
113876
+ function computeExponentialRetryDelayMs(attempt, retryDelayMs, maxRetryDelayMs) {
113877
+ const exponent = Math.min(Math.max(0, attempt), MAX_RETRY_EXPONENT);
113878
+ return Math.min(retryDelayMs * 2 ** exponent, maxRetryDelayMs);
113879
+ }
113880
+ var MAX_RETRY_EXPONENT = 20;
113881
+
113882
+ // src/daemon/infrastructure/outbox/lib/coalescing-state-outbox.ts
113883
+ function createCoalescingStateOutbox(options) {
113884
+ const durable = [options.store, options.deliveryKey, options.serialize, options.deserialize];
113885
+ if (durable.some(Boolean) && durable.some((value) => !value))
113886
+ throw new Error("Durable outbox requires store, deliveryKey, serialize, and deserialize");
113887
+ const minIntervalMs = options.minIntervalMs ?? DEFAULT_MIN_INTERVAL_MS;
113888
+ const retryDelayMs = options.retryDelayMs ?? DEFAULT_RETRY_DELAY_MS;
113889
+ const maxRetryDelayMs = options.maxRetryDelayMs ?? DEFAULT_MAX_RETRY_DELAY_MS;
113890
+ let pending3 = null;
113891
+ let inFlight2 = null;
113892
+ let timer = null;
113893
+ let lastSentAt = 0;
113894
+ let retryAttempt = 0;
113895
+ let stopped = false;
113896
+ if (options.store && options.deliveryKey && options.deserialize) {
113897
+ const recovered = options.store.getPending(options.deliveryKey);
113898
+ if (recovered) {
113899
+ pending3 = { state: options.deserialize(recovered.payloadJson), waiters: [] };
113900
+ retryAttempt = recovered.attempts;
113901
+ }
113902
+ }
113903
+ const rejectWaiters = (waiters, error51) => {
113904
+ for (const waiter of waiters)
113905
+ waiter.reject(error51);
113906
+ };
113907
+ const mergePending = (older, newer) => ({
113908
+ state: newer?.state ?? older.state,
113909
+ waiters: [...older.waiters, ...newer?.waiters ?? []]
113910
+ });
113911
+ const clearTimer = () => {
113912
+ if (timer)
113913
+ clearTimeout(timer);
113914
+ timer = null;
113915
+ };
113916
+ const schedule2 = (delayMs) => {
113917
+ if (stopped || !pending3 || inFlight2 || timer)
113918
+ return;
113919
+ timer = setTimeout(() => {
113920
+ timer = null;
113921
+ drain2().catch(() => {
113922
+ return;
113923
+ });
113924
+ }, Math.max(0, delayMs));
113925
+ timer.unref?.();
113926
+ };
113927
+ if (pending3) {
113928
+ schedule2(retryAttempt > 0 ? computeExponentialRetryDelayMs(retryAttempt - 1, retryDelayMs, maxRetryDelayMs) : 0);
113929
+ }
113930
+ async function drain2() {
113931
+ if (stopped || !pending3 || inFlight2)
113932
+ return;
113933
+ const batch = pending3;
113934
+ pending3 = null;
113935
+ const sendPromise = Promise.resolve().then(() => options.send(batch.state));
113936
+ inFlight2 = { ...batch, promise: sendPromise };
113937
+ let retryDelay = null;
113938
+ const store = options.store;
113939
+ const deliveryKey = options.deliveryKey;
113940
+ try {
113941
+ const result = await sendPromise;
113942
+ lastSentAt = Date.now();
113943
+ retryAttempt = 0;
113944
+ if (store && deliveryKey)
113945
+ store.markDone(deliveryKey);
113946
+ for (const waiter of batch.waiters)
113947
+ waiter.resolve(result);
113948
+ } catch (error51) {
113949
+ options.onError?.(error51);
113950
+ if (store && deliveryKey)
113951
+ store.markPendingRetry(deliveryKey, error51);
113952
+ pending3 = mergePending(batch, pending3);
113953
+ retryDelay = computeExponentialRetryDelayMs(retryAttempt, retryDelayMs, maxRetryDelayMs);
113954
+ retryAttempt++;
113955
+ throw error51;
113956
+ } finally {
113957
+ inFlight2 = null;
113958
+ if (pending3) {
113959
+ const intervalDelay = Math.max(0, minIntervalMs - (Date.now() - lastSentAt));
113960
+ schedule2(retryDelay ?? intervalDelay);
113961
+ }
113962
+ }
113963
+ }
113964
+ const enqueue = (state) => {
113965
+ if (stopped)
113966
+ return Promise.reject(new Error("Outbox is stopped"));
113967
+ const promise4 = new Promise((resolve8, reject) => {
113968
+ const waiter = { resolve: resolve8, reject };
113969
+ if (pending3) {
113970
+ pending3 = { state, waiters: [...pending3.waiters, waiter] };
113971
+ } else {
113972
+ pending3 = { state, waiters: [waiter] };
113973
+ }
113974
+ if (options.store && options.deliveryKey && options.serialize) {
113975
+ options.store.upsertPending(options.deliveryKey, options.serialize(state));
113976
+ }
113977
+ });
113978
+ if (!inFlight2 && !timer) {
113979
+ const delay3 = lastSentAt === 0 ? 0 : Math.max(0, minIntervalMs - (Date.now() - lastSentAt));
113980
+ schedule2(delay3);
113981
+ }
113982
+ return promise4;
113983
+ };
113984
+ const flushNow = async () => {
113985
+ if (stopped)
113986
+ return;
113987
+ clearTimer();
113988
+ if (inFlight2) {
113989
+ await inFlight2.promise.catch(() => {
113990
+ return;
113991
+ });
113992
+ }
113993
+ if (pending3)
113994
+ await drain2();
113995
+ };
113996
+ const stop4 = async () => {
113997
+ if (stopped)
113998
+ return;
113999
+ await flushNow();
114000
+ stopped = true;
114001
+ clearTimer();
114002
+ if (inFlight2)
114003
+ await inFlight2.promise.catch(() => {
114004
+ return;
114005
+ });
114006
+ const unsent = pending3;
114007
+ pending3 = null;
114008
+ if (unsent)
114009
+ rejectWaiters(unsent.waiters, new Error("Outbox stopped before send completed"));
114010
+ };
114011
+ return { enqueue, flushNow, stop: stop4 };
114012
+ }
114013
+ var DEFAULT_MIN_INTERVAL_MS = 5000, DEFAULT_RETRY_DELAY_MS = 500, DEFAULT_MAX_RETRY_DELAY_MS = 5000;
114014
+ var init_coalescing_state_outbox = () => {};
114015
+
114016
+ // src/daemon/infrastructure/outbox/lib/keyed-coalescing-state-outbox-registry.ts
114017
+ function createKeyedCoalescingStateOutboxRegistry(options) {
114018
+ const outboxes = new Map;
114019
+ const getOrCreate = (key) => {
114020
+ let outbox = outboxes.get(key);
114021
+ if (!outbox) {
114022
+ outbox = createCoalescingStateOutbox({
114023
+ send: (state) => options.createSend(key)(state),
114024
+ minIntervalMs: options.minIntervalMs,
114025
+ retryDelayMs: options.retryDelayMs,
114026
+ maxRetryDelayMs: options.maxRetryDelayMs,
114027
+ onError: (error51) => options.onError?.(key, error51),
114028
+ ...options.store ? { store: options.store, deliveryKey: key, serialize: options.serialize, deserialize: options.deserialize } : {}
114029
+ });
114030
+ outboxes.set(key, outbox);
114031
+ }
114032
+ return outbox;
114033
+ };
114034
+ const stop4 = async (key) => {
114035
+ const outbox = outboxes.get(key);
114036
+ outboxes.delete(key);
114037
+ await outbox?.flushNow().catch(() => {
114038
+ return;
114039
+ });
114040
+ await outbox?.stop().catch(() => {
114041
+ return;
114042
+ });
114043
+ };
114044
+ return {
114045
+ enqueue: (key, state) => getOrCreate(key).enqueue(state),
114046
+ stop: stop4,
114047
+ stopAll: async () => {
114048
+ for (const key of [...outboxes.keys()])
114049
+ await stop4(key);
114050
+ options.store?.close();
114051
+ }
114052
+ };
114053
+ }
114054
+ var init_keyed_coalescing_state_outbox_registry = __esm(() => {
114055
+ init_coalescing_state_outbox();
114056
+ });
114057
+
114058
+ // src/daemon/infrastructure/outbox/outbox-db-path.ts
114059
+ import { homedir as homedir9 } from "node:os";
114060
+ import { join as join25 } from "node:path";
114061
+ function resolveOutboxDbPath(machineId, kind) {
114062
+ return join25(homedir9(), ".chatroom", "daemon", machineId, `outbox-${kind}.sqlite`);
114063
+ }
114064
+ var init_outbox_db_path = () => {};
114065
+
114066
+ // src/daemon/infrastructure/outbox/workspace-file-tree-checkpoint-outbox.ts
114067
+ function createWorkspaceFileTreeCheckpointOutboxRegistry(machineId, createSend, options) {
114068
+ return createKeyedCoalescingStateOutboxRegistry({
114069
+ store: openDurableCoalescingStateStore(resolveOutboxDbPath(machineId, "file-tree-checkpoint")),
114070
+ serialize: JSON.stringify,
114071
+ deserialize: JSON.parse,
114072
+ createSend,
114073
+ minIntervalMs: WORKSPACE_FILE_TREE_CHECKPOINT_OUTBOX_MIN_INTERVAL_MS,
114074
+ retryDelayMs: WORKSPACE_FILE_TREE_CHECKPOINT_OUTBOX_RETRY_DELAY_MS,
114075
+ maxRetryDelayMs: WORKSPACE_FILE_TREE_CHECKPOINT_OUTBOX_MAX_RETRY_DELAY_MS,
114076
+ onError: options?.onError
114077
+ });
114078
+ }
114079
+ var WORKSPACE_FILE_TREE_CHECKPOINT_OUTBOX_MIN_INTERVAL_MS = 5000, WORKSPACE_FILE_TREE_CHECKPOINT_OUTBOX_RETRY_DELAY_MS = 5000, WORKSPACE_FILE_TREE_CHECKPOINT_OUTBOX_MAX_RETRY_DELAY_MS;
114080
+ var init_workspace_file_tree_checkpoint_outbox = __esm(() => {
114081
+ init_durable_coalescing_state_store();
114082
+ init_keyed_coalescing_state_outbox_registry();
114083
+ init_outbox_db_path();
114084
+ WORKSPACE_FILE_TREE_CHECKPOINT_OUTBOX_MAX_RETRY_DELAY_MS = 5 * 60000;
114085
+ });
114086
+
114087
+ // src/daemon/infrastructure/outbox/lib/durable-fifo-queue-schema.ts
114088
+ var DURABLE_FIFO_QUEUE_MIGRATIONS;
114089
+ var init_durable_fifo_queue_schema = __esm(() => {
114090
+ DURABLE_FIFO_QUEUE_MIGRATIONS = [
114091
+ `CREATE TABLE IF NOT EXISTS schema_meta (key TEXT PRIMARY KEY, value TEXT NOT NULL)`,
114092
+ `CREATE TABLE IF NOT EXISTS fifo_outbox_entries (id INTEGER PRIMARY KEY AUTOINCREMENT, delivery_key TEXT NOT NULL, payload_json TEXT NOT NULL, status TEXT NOT NULL DEFAULT 'pending', attempts INTEGER NOT NULL DEFAULT 0, last_error TEXT, created_at INTEGER NOT NULL, updated_at INTEGER NOT NULL)`,
114093
+ `CREATE INDEX IF NOT EXISTS idx_fifo_outbox_pending ON fifo_outbox_entries(delivery_key, status, id)`
114094
+ ];
114095
+ });
114096
+
114097
+ // src/daemon/infrastructure/outbox/lib/durable-fifo-queue-store.ts
114098
+ import { DatabaseSync as DatabaseSync2 } from "node:sqlite";
114099
+ import { mkdirSync as mkdirSync7 } from "node:fs";
114100
+ import { dirname as dirname13 } from "node:path";
114101
+ function openDurableFifoQueueStore(dbPath) {
114102
+ mkdirSync7(dirname13(dbPath), { recursive: true });
114103
+ const db = new DatabaseSync2(dbPath);
114104
+ for (const sql of DURABLE_FIFO_QUEUE_MIGRATIONS)
114105
+ db.exec(sql);
114106
+ db.prepare("UPDATE fifo_outbox_entries SET status='pending', updated_at=? WHERE status='in_flight'").run(Date.now());
114107
+ return {
114108
+ enqueue: (key, payloadJson) => {
114109
+ const now = Date.now();
114110
+ return Number(db.prepare("INSERT INTO fifo_outbox_entries(delivery_key,payload_json,created_at,updated_at) VALUES(?,?,?,?) RETURNING id").get(key, payloadJson, now, now).id);
114111
+ },
114112
+ claimNextBatch: (key, limit) => db.prepare("UPDATE fifo_outbox_entries SET status='in_flight', attempts=attempts+1, updated_at=? WHERE id IN (SELECT id FROM fifo_outbox_entries WHERE delivery_key=? AND status='pending' ORDER BY id LIMIT ?) RETURNING id, delivery_key as deliveryKey, payload_json as payloadJson, attempts").all(Date.now(), key, limit),
114113
+ markDone: (id3) => {
114114
+ db.prepare("DELETE FROM fifo_outbox_entries WHERE id=?").run(id3);
114115
+ },
114116
+ markPending: (id3) => {
114117
+ db.prepare("UPDATE fifo_outbox_entries SET status='pending', last_error=NULL, updated_at=? WHERE id=?").run(Date.now(), id3);
114118
+ },
114119
+ updatePayload: (id3, payloadJson) => {
114120
+ db.prepare("UPDATE fifo_outbox_entries SET payload_json=?, updated_at=? WHERE id=?").run(payloadJson, Date.now(), id3);
114121
+ },
114122
+ markPendingRetry: (id3, error51) => {
114123
+ db.prepare("UPDATE fifo_outbox_entries SET status='pending', last_error=?, updated_at=? WHERE id=?").run(String(error51), Date.now(), id3);
114124
+ },
114125
+ listPendingForRecovery: (key) => db.prepare("SELECT id, delivery_key as deliveryKey, payload_json as payloadJson, attempts FROM fifo_outbox_entries WHERE delivery_key=? AND status IN ('pending','in_flight') ORDER BY id").all(key),
114126
+ close: () => db.close()
114127
+ };
114128
+ }
114129
+ var init_durable_fifo_queue_store = __esm(() => {
114130
+ init_durable_fifo_queue_schema();
114131
+ });
114132
+
114133
+ // src/daemon/infrastructure/outbox/lib/fifo-batched-outbox.ts
114134
+ function createFifoBatchedOutbox(o) {
114135
+ const waiters = new Map;
114136
+ let running3;
114137
+ let stopped = false;
114138
+ let retryTimer;
114139
+ let retryAttempt = 0;
114140
+ const retryDelay = () => computeExponentialRetryDelayMs(retryAttempt++, o.retryDelayMs ?? 500, o.maxRetryDelayMs ?? 5000);
114141
+ const scheduleRetry = () => {
114142
+ if (!stopped && !retryTimer) {
114143
+ retryTimer = setTimeout(() => {
114144
+ retryTimer = undefined;
114145
+ drain2().catch(() => {
114146
+ return;
114147
+ });
114148
+ }, retryDelay());
114149
+ retryTimer.unref?.();
114150
+ }
114151
+ };
114152
+ const drain2 = async () => {
114153
+ if (running3)
114154
+ return running3;
114155
+ running3 = (async () => {
114156
+ while (true) {
114157
+ const rows2 = o.store.claimNextBatch(o.deliveryKey, o.batchSize);
114158
+ if (!rows2.length)
114159
+ break;
114160
+ try {
114161
+ const results = await o.send(rows2.map((r) => o.deserialize(r.payloadJson)));
114162
+ let hasRetry = false;
114163
+ for (let i2 = 0;i2 < results.length; i2++) {
114164
+ const item = o.deserialize(rows2[i2].payloadJson);
114165
+ const outcome = o.classifyOutcome?.(results[i2], item) ?? { kind: "success" };
114166
+ if (outcome.kind === "retry") {
114167
+ o.store.updatePayload(rows2[i2].id, o.serialize(outcome.item));
114168
+ o.store.markPending(rows2[i2].id);
114169
+ hasRetry = true;
114170
+ continue;
114171
+ }
114172
+ o.store.markDone(rows2[i2].id);
114173
+ waiters.get(rows2[i2].id)?.resolve(results[i2]);
114174
+ waiters.delete(rows2[i2].id);
114175
+ }
114176
+ for (let i2 = results.length;i2 < rows2.length; i2++)
114177
+ o.store.markPending(rows2[i2].id);
114178
+ if (hasRetry) {
114179
+ scheduleRetry();
114180
+ break;
114181
+ }
114182
+ retryAttempt = 0;
114183
+ } catch (e) {
114184
+ o.onError?.(e);
114185
+ for (const r of rows2)
114186
+ o.store.markPendingRetry(r.id, e);
114187
+ scheduleRetry();
114188
+ break;
114189
+ }
114190
+ }
114191
+ })().finally(() => {
114192
+ running3 = undefined;
114193
+ });
114194
+ return running3;
114195
+ };
114196
+ const enqueue = (item) => {
114197
+ if (stopped)
114198
+ return Promise.reject(new Error("Outbox is stopped"));
114199
+ const id3 = o.store.enqueue(o.deliveryKey, o.serialize(item));
114200
+ const p = new Promise((resolve8, reject) => waiters.set(id3, { resolve: resolve8, reject }));
114201
+ drain2().catch(() => {
114202
+ return;
114203
+ });
114204
+ return p;
114205
+ };
114206
+ const flushNow = async () => {
114207
+ while (o.store.listPendingForRecovery(o.deliveryKey).length) {
114208
+ await drain2();
114209
+ }
114210
+ };
114211
+ const stop4 = async () => {
114212
+ if (stopped)
114213
+ return;
114214
+ if (retryTimer)
114215
+ clearTimeout(retryTimer);
114216
+ retryTimer = undefined;
114217
+ await flushNow();
114218
+ stopped = true;
114219
+ };
114220
+ return { enqueue, flushNow, stop: stop4 };
114221
+ }
114222
+ var init_fifo_batched_outbox = () => {};
114223
+
114224
+ // src/daemon/infrastructure/outbox/lib/keyed-fifo-batched-outbox-registry.ts
114225
+ function createKeyedFifoBatchedOutboxRegistry(o) {
114226
+ const boxes = new Map;
114227
+ const get13 = (key) => {
114228
+ let b = boxes.get(key);
114229
+ if (!b) {
114230
+ b = createFifoBatchedOutbox({
114231
+ batchSize: o.batchSize,
114232
+ send: o.createSend(key),
114233
+ store: o.store,
114234
+ deliveryKey: key,
114235
+ serialize: o.serialize,
114236
+ deserialize: o.deserialize,
114237
+ retryDelayMs: o.retryDelayMs,
114238
+ maxRetryDelayMs: o.maxRetryDelayMs,
114239
+ onError: (e) => o.onError?.(key, e),
114240
+ classifyOutcome: o.classifyOutcome
114241
+ });
114242
+ boxes.set(key, b);
114243
+ }
114244
+ return b;
114245
+ };
114246
+ const stop4 = async (k) => {
114247
+ const b = boxes.get(k);
114248
+ if (b) {
114249
+ await b.stop();
114250
+ boxes.delete(k);
114251
+ }
114252
+ };
114253
+ return {
114254
+ enqueue: (k, i2) => get13(k).enqueue(i2),
114255
+ flushNow: async (k) => {
114256
+ if (k)
114257
+ await get13(k).flushNow();
114258
+ else
114259
+ for (const b of boxes.values())
114260
+ await b.flushNow();
114261
+ },
114262
+ stop: stop4,
114263
+ stopAll: async () => {
114264
+ for (const k of [...boxes.keys()])
114265
+ await stop4(k);
114266
+ o.store.close();
114267
+ }
114268
+ };
114269
+ }
114270
+ var init_keyed_fifo_batched_outbox_registry = __esm(() => {
114271
+ init_fifo_batched_outbox();
114272
+ });
114273
+
114274
+ // src/daemon/infrastructure/outbox/workspace-file-tree-delta-outbox.ts
114275
+ function createWorkspaceFileTreeDeltaOutboxRegistry(machineId, createSend, options) {
114276
+ const store = openDurableFifoQueueStore(resolveOutboxDbPath(machineId, "file-tree-delta"));
114277
+ return createKeyedFifoBatchedOutboxRegistry({
114278
+ store,
114279
+ batchSize: options?.batchSize ?? WORKSPACE_FILE_TREE_DELTA_OUTBOX_BATCH_SIZE,
114280
+ createSend: (key) => async (units) => {
114281
+ const out = [];
114282
+ for (const u of units) {
114283
+ const r = await createSend(key)(u);
114284
+ out.push(r);
114285
+ }
114286
+ return out;
114287
+ },
114288
+ serialize: JSON.stringify,
114289
+ deserialize: JSON.parse,
114290
+ retryDelayMs: WORKSPACE_FILE_TREE_DELTA_OUTBOX_RETRY_DELAY_MS,
114291
+ maxRetryDelayMs: WORKSPACE_FILE_TREE_DELTA_OUTBOX_MAX_RETRY_DELAY_MS,
114292
+ onError: options?.onError,
114293
+ classifyOutcome: (result, unit) => result.status === "conflict" ? { kind: "retry", item: { ...unit, baseRevision: result.revision } } : { kind: "success" }
114294
+ });
114295
+ }
114296
+ var WORKSPACE_FILE_TREE_DELTA_OUTBOX_BATCH_SIZE = 5, WORKSPACE_FILE_TREE_DELTA_OUTBOX_RETRY_DELAY_MS = 5000, WORKSPACE_FILE_TREE_DELTA_OUTBOX_MAX_RETRY_DELAY_MS;
114297
+ var init_workspace_file_tree_delta_outbox = __esm(() => {
114298
+ init_durable_fifo_queue_store();
114299
+ init_keyed_fifo_batched_outbox_registry();
114300
+ init_outbox_db_path();
114301
+ WORKSPACE_FILE_TREE_DELTA_OUTBOX_MAX_RETRY_DELAY_MS = 5 * 60000;
114302
+ });
114303
+
114304
+ // src/daemon/infrastructure/outbox/index.ts
114305
+ var init_outbox = __esm(() => {
114306
+ init_workspace_file_tree_checkpoint_outbox();
114307
+ init_workspace_file_tree_delta_outbox();
114308
+ });
114309
+
114310
+ // ../../services/backend/src/domain/workspace-file-tree/types.ts
114311
+ var MAX_TREE_JSON_BYTES;
114312
+ var init_types2 = __esm(() => {
114313
+ MAX_TREE_JSON_BYTES = 900 * 1024;
114314
+ });
114315
+ // ../../services/backend/src/domain/workspace-file-tree/select-strategy.ts
114316
+ function treeJsonByteLength(tree) {
114317
+ return Buffer.byteLength(JSON.stringify(tree), "utf8");
114318
+ }
114319
+ function selectFileTreeSnapshotStrategyId(tree) {
114320
+ return treeJsonByteLength(tree) > MAX_TREE_JSON_BYTES ? "sharded" : "blob";
114321
+ }
114322
+ var init_select_strategy = __esm(() => {
114323
+ init_types2();
114324
+ });
114325
+
114326
+ // ../../services/backend/src/domain/workspace-file-tree/registry.ts
114327
+ var init_registry5 = __esm(() => {
114328
+ init_select_strategy();
114329
+ });
114330
+ // ../../services/backend/src/domain/workspace-file-tree/transport/blob-snapshot.ts
114331
+ function toLegacyBlobSyncArgs(payload) {
114332
+ return { data: payload.data, dataHash: payload.dataHash, scannedAt: payload.scannedAt };
114333
+ }
114334
+
114335
+ // ../../services/backend/src/domain/workspace-file-tree/transport/sharded-snapshot.ts
114336
+ function toLegacyShardBatchItem(shard) {
114337
+ return { ...shard };
114338
+ }
114339
+ function toLegacyManifestSyncArgs(manifest) {
114340
+ return { ...manifest };
114341
+ }
114342
+ // ../../services/backend/src/domain/workspace-file-tree/transport/index.ts
114343
+ var init_transport = () => {};
114344
+
114345
+ // ../../services/backend/src/domain/workspace-file-tree/index.ts
114346
+ var init_workspace_file_tree = __esm(() => {
114347
+ init_types2();
114348
+ init_select_strategy();
114349
+ init_registry5();
114350
+ init_transport();
114351
+ });
114352
+
114353
+ // src/infrastructure/services/workspace/transport/blob-snapshot-publish.ts
114354
+ import { gzipSync as gzipSync2 } from "node:zlib";
114355
+ function buildBlobSnapshotPayload(tree, dataHash) {
114356
+ const compressed = gzipSync2(Buffer.from(JSON.stringify(tree))).toString("base64");
114357
+ return {
114358
+ data: { compression: "gzip", content: compressed },
114359
+ dataHash,
114360
+ scannedAt: tree.scannedAt
114361
+ };
114362
+ }
114363
+ async function publishBlobSnapshot(session2, workingDir, payload) {
114364
+ await session2.backend.mutation(api.workspaceFiles.syncFileTreeV2, {
114365
+ sessionId: session2.sessionId,
114366
+ machineId: session2.machineId,
114367
+ workingDir,
114368
+ ...toLegacyBlobSyncArgs(payload)
114369
+ });
114370
+ return {
114371
+ strategyId: "blob",
114372
+ snapshotId: payload.dataHash,
114373
+ scannedAt: payload.scannedAt,
114374
+ entryCount: 0
114375
+ };
114376
+ }
114377
+ var init_blob_snapshot_publish = __esm(() => {
114378
+ init_api3();
114379
+ });
114380
+
114381
+ // src/infrastructure/services/workspace/file-tree-partition.ts
114382
+ import { createHash as createHash8 } from "node:crypto";
114383
+ import { gzipSync as gzipSync3 } from "node:zlib";
114384
+ function computeShardDataHash(payload) {
114385
+ return createHash8("md5").update(JSON.stringify(payload)).digest("hex");
114386
+ }
114387
+ function shardIdForPath(path8) {
114388
+ const slash = path8.indexOf("/");
114389
+ return slash === -1 ? "__root__" : path8.slice(0, slash);
114390
+ }
114391
+ function childShardId(path8, parentShardId) {
114392
+ if (parentShardId === "__root__") {
114393
+ return shardIdForPath(path8);
114394
+ }
114395
+ if (path8 === parentShardId) {
114396
+ return parentShardId;
114397
+ }
114398
+ const prefix = `${parentShardId}/`;
114399
+ if (!path8.startsWith(prefix)) {
114400
+ return parentShardId;
114401
+ }
114402
+ const remainder = path8.slice(prefix.length);
114403
+ const slash = remainder.indexOf("/");
114404
+ return slash === -1 ? parentShardId : `${parentShardId}/${remainder.slice(0, slash)}`;
114405
+ }
114406
+ function groupEntriesByShardId(entries2, parentShardId) {
114407
+ const groups = new Map;
114408
+ for (const entry of entries2) {
114409
+ const shardId = parentShardId === "__root__" ? shardIdForPath(entry.path) : childShardId(entry.path, parentShardId);
114410
+ const group = groups.get(shardId) ?? [];
114411
+ group.push(entry);
114412
+ groups.set(shardId, group);
114413
+ }
114414
+ return groups;
114415
+ }
114416
+ function buildPreparedShard(shardId, payload) {
114417
+ const compressed = gzipSync3(Buffer.from(JSON.stringify(payload))).toString("base64");
114418
+ return {
114419
+ shardId,
114420
+ payload,
114421
+ dataHash: computeShardDataHash(payload),
114422
+ entryCount: payload.entries.length,
114423
+ data: { compression: "gzip", content: compressed }
114424
+ };
114425
+ }
114426
+ function subdivideShardGroup(subgroups, tree) {
114427
+ const shards = [];
114428
+ for (const [subId, subEntries] of subgroups) {
114429
+ shards.push(...prepareShardGroup(subEntries, subId, tree));
114430
+ }
114431
+ return shards;
114432
+ }
114433
+ function shouldSkipParentCompression(subgroups, entryCount) {
114434
+ return subgroups.size > 1 && entryCount > LARGE_SHARD_ENTRY_THRESHOLD;
114435
+ }
114436
+ function prepareShardGroup(entries2, shardId, tree) {
114437
+ const subgroups = groupEntriesByShardId(entries2, shardId);
114438
+ if (shouldSkipParentCompression(subgroups, entries2.length)) {
114439
+ return subdivideShardGroup(subgroups, tree);
114440
+ }
114441
+ const payload = {
114442
+ entries: entries2,
114443
+ scannedAt: tree.scannedAt,
114444
+ rootDir: tree.rootDir
114445
+ };
114446
+ const compressed = gzipSync3(Buffer.from(JSON.stringify(payload))).toString("base64");
114447
+ if (Buffer.byteLength(compressed, "utf8") <= MAX_SHARD_JSON_BYTES || subgroups.size <= 1) {
114448
+ return [buildPreparedShard(shardId, payload)];
114449
+ }
114450
+ return subdivideShardGroup(subgroups, tree);
114451
+ }
114452
+ function partitionFileTree(tree) {
114453
+ const topGroups = groupEntriesByShardId(tree.entries, "__root__");
114454
+ const shards = [];
114455
+ for (const [shardId, entries2] of topGroups) {
114456
+ shards.push(...prepareShardGroup(entries2, shardId, tree));
114457
+ }
114458
+ return shards;
114459
+ }
114460
+ var MAX_TREE_JSON_BYTES2, MAX_SHARD_JSON_BYTES, MAX_SHARD_BATCH_SIZE = 8, LARGE_SHARD_ENTRY_THRESHOLD = 50000;
114461
+ var init_file_tree_partition = __esm(() => {
114462
+ init_workspace_file_tree();
114463
+ MAX_TREE_JSON_BYTES2 = 900 * 1024;
114464
+ MAX_SHARD_JSON_BYTES = 800 * 1024;
114465
+ });
114466
+
114467
+ // src/infrastructure/services/workspace/transport/sharded-snapshot-publish.ts
114468
+ async function publishShardedSnapshot(session2, workingDir, tree, syncGeneration) {
114469
+ const shards = partitionFileTree(tree);
114470
+ const shardIds = [];
114471
+ for (let i2 = 0;i2 < shards.length; i2 += MAX_SHARD_BATCH_SIZE) {
114472
+ const batch = shards.slice(i2, i2 + MAX_SHARD_BATCH_SIZE);
114473
+ const items = batch.map((s) => ({
114474
+ shardId: s.shardId,
114475
+ data: s.data,
114476
+ dataHash: s.dataHash,
114477
+ scannedAt: tree.scannedAt,
114478
+ entryCount: s.entryCount
114479
+ }));
114480
+ await session2.backend.mutation(api.workspaceFiles.syncFileTreeShardV3Batch, {
114481
+ sessionId: session2.sessionId,
114482
+ machineId: session2.machineId,
114483
+ workingDir,
114484
+ syncGeneration,
114485
+ items: items.map(toLegacyShardBatchItem)
113650
114486
  });
113651
- changeSource = fs12;
113652
- await fs12.ready;
113653
- console.log("[workspace-file-tree] change source: fs (degraded from git)");
114487
+ for (const s of batch)
114488
+ shardIds.push(s.shardId);
114489
+ }
114490
+ const manifest = {
114491
+ syncGeneration,
114492
+ shardIds,
114493
+ totalEntryCount: tree.entries.length,
114494
+ complete: true,
114495
+ scannedAt: tree.scannedAt
113654
114496
  };
113655
- const change = await createWorkspaceChangeSource({
114497
+ await session2.backend.mutation(api.workspaceFiles.syncFileTreeManifestV3, {
114498
+ sessionId: session2.sessionId,
114499
+ machineId: session2.machineId,
113656
114500
  workingDir,
113657
- pollIntervalMs: options.changeSourcePollIntervalMs,
113658
- shouldIgnore: shouldIgnorePath,
113659
- getKnownPaths: () => manifest.paths,
113660
- onEvents: handleChangeSourceEvents,
113661
- onNeedsReconcile: () => enqueueSerial(reconcileNow),
113662
- onError: handleChangeSourceError,
113663
- onPersistentFailure: () => degradeGitToFs("persistent git poll failures")
114501
+ ...toLegacyManifestSyncArgs(manifest)
113664
114502
  });
113665
- changeSource = change.source;
113666
- changeSourceMode = change.mode;
113667
- if (change.mode === "git") {
113668
- console.log(`[workspace-file-tree] change source: git (${change.gitRepoCount ?? 1} repo${(change.gitRepoCount ?? 1) === 1 ? "" : "s"})`);
113669
- } else {
113670
- console.log("[workspace-file-tree] change source: fs");
113671
- }
113672
- await changeSource.ready;
113673
- scheduleReconcile();
113674
114503
  return {
113675
- workingDir,
113676
- getManifest: () => manifest,
113677
- getTree: () => treeFromManifest(manifest),
113678
- checkpoint: () => enqueueSerial(publishCheckpoint),
113679
- reconcile: () => enqueueSerial(reconcileNow),
113680
- stop: async () => {
113681
- stopped = true;
113682
- if (reconcileTimer)
113683
- clearTimeout(reconcileTimer);
113684
- reconcileTimer = null;
113685
- await changeSource?.stop();
113686
- changeSource = null;
113687
- await serial;
113688
- await saveWorkspaceSyncManifest(manifest);
113689
- }
114504
+ strategyId: "sharded",
114505
+ snapshotId: syncGeneration,
114506
+ scannedAt: tree.scannedAt,
114507
+ entryCount: tree.entries.length
113690
114508
  };
113691
114509
  }
113692
- var DEFAULT_RECONCILE_INTERVAL_MS, DEFAULT_CHECKPOINT_EVERY_REVISIONS = 100, RECONCILE_JITTER_RATIO = 0.2, MAX_DELTA_OPERATIONS = 100;
113693
- var init_workspace_file_tree_coordinator = __esm(() => {
113694
- init_file_tree_data_hash();
113695
- init_file_tree_scanner();
113696
- init_git_workspace_porcelain();
113697
- init_workspace_change_source();
113698
- init_workspace_fs_watcher();
113699
- init_workspace_ignore();
113700
- init_workspace_sync_state();
113701
- DEFAULT_RECONCILE_INTERVAL_MS = 10 * 60 * 1000;
114510
+ var init_sharded_snapshot_publish = __esm(() => {
114511
+ init_api3();
114512
+ init_file_tree_partition();
113702
114513
  });
113703
114514
 
113704
- // src/infrastructure/services/workspace/workspace-sync-config.ts
113705
- var FILE_TREE_SYNC_DEBOUNCE_MS = 5000;
113706
-
113707
- // src/infrastructure/services/workspace/workspace-sync-queue.ts
113708
- function queueKey(machineId, workingDir) {
113709
- return `${machineId}\x00${workingDir}`;
114515
+ // src/daemon/infrastructure/outbox/workspace-file-tree-checkpoint-send.ts
114516
+ import { randomUUID as randomUUID11 } from "node:crypto";
114517
+ function needsMoreCheckpointPrune(result) {
114518
+ return (result.status === "published" || result.status === "unchanged") && result.pruneComplete === false;
113710
114519
  }
113711
- function getOrCreateState(key) {
113712
- let state = queues.get(key);
113713
- if (!state) {
113714
- state = { drainPromise: null, pendingTask: null, scheduled: false };
113715
- queues.set(key, state);
114520
+ function assertCheckpointAccepted(result) {
114521
+ if (result.status === "snapshot-missing" || result.status === "resync-required") {
114522
+ throw new Error(`File tree checkpoint rejected: ${result.status}`);
113716
114523
  }
113717
- return state;
113718
114524
  }
113719
- function sleep7(ms) {
113720
- return new Promise((resolve8) => setTimeout(resolve8, ms));
113721
- }
113722
- async function drainQueue(state, key, debounceMs) {
113723
- try {
113724
- while (state.pendingTask) {
113725
- const lastCompletedAt = lastCompletedAtByKey.get(key) ?? 0;
113726
- const elapsed3 = Date.now() - lastCompletedAt;
113727
- const waitMs = lastCompletedAt === 0 ? 0 : Math.max(0, debounceMs - elapsed3);
113728
- if (waitMs > 0) {
113729
- await sleep7(waitMs);
113730
- }
113731
- const task = state.pendingTask;
113732
- if (!task)
113733
- break;
113734
- state.pendingTask = null;
113735
- await task();
113736
- lastCompletedAtByKey.set(key, Date.now());
113737
- }
113738
- } finally {
113739
- state.drainPromise = null;
113740
- state.scheduled = false;
113741
- if (state.pendingTask) {
113742
- kickDrain(state, key, debounceMs);
113743
- } else {
113744
- queues.delete(key);
113745
- }
114525
+ async function syncScannedFileTree(session2, normalizedWorkingDir, tree, dataHash, syncGeneration) {
114526
+ if (selectFileTreeSnapshotStrategyId(tree) === "sharded") {
114527
+ const ref2 = await publishShardedSnapshot(session2, normalizedWorkingDir, tree, syncGeneration);
114528
+ return { strategyId: ref2.strategyId, snapshotId: ref2.snapshotId };
113746
114529
  }
114530
+ const ref = await publishBlobSnapshot(session2, normalizedWorkingDir, buildBlobSnapshotPayload(tree, dataHash));
114531
+ return { strategyId: ref.strategyId, snapshotId: ref.snapshotId };
113747
114532
  }
113748
- function kickDrain(state, key, debounceMs) {
113749
- if (state.scheduled || state.drainPromise)
113750
- return;
113751
- state.scheduled = true;
113752
- state.drainPromise = new Promise((resolve8, reject) => {
113753
- queueMicrotask(() => {
113754
- drainQueue(state, key, debounceMs).then(resolve8, reject);
113755
- });
114533
+ async function publishCheckpointUntilPruned(session2, normalizedWorkingDir, snapshot, revision) {
114534
+ let checkpointRevision = revision;
114535
+ const publish = () => session2.backend.mutation(api.workspaceFiles.publishFileTreeCheckpoint, {
114536
+ sessionId: session2.sessionId,
114537
+ machineId: session2.machineId,
114538
+ workingDir: normalizedWorkingDir,
114539
+ revision: checkpointRevision,
114540
+ ...snapshot
113756
114541
  });
114542
+ let result = await publish();
114543
+ if (result.status === "resync-required") {
114544
+ checkpointRevision = result.expectedRevision + 1;
114545
+ result = await publish();
114546
+ }
114547
+ while (needsMoreCheckpointPrune(result))
114548
+ result = await publish();
114549
+ assertCheckpointAccepted(result);
114550
+ return checkpointRevision;
113757
114551
  }
113758
- async function enqueueFileTreeSync(machineId, workingDir, task, options) {
113759
- const debounceMs = options?.debounceMs ?? FILE_TREE_SYNC_DEBOUNCE_MS;
113760
- const key = queueKey(machineId, workingDir);
113761
- const state = getOrCreateState(key);
113762
- state.pendingTask = task;
113763
- kickDrain(state, key, debounceMs);
113764
- return state.drainPromise ?? Promise.resolve();
114552
+ function createWorkspaceFileTreeCheckpointSend(session2, normalizedWorkingDir) {
114553
+ return async (state) => {
114554
+ const snapshot = await syncScannedFileTree(session2, normalizedWorkingDir, state.tree, computeFileTreeDataHash(state.tree), randomUUID11());
114555
+ const revision = await publishCheckpointUntilPruned(session2, normalizedWorkingDir, snapshot, state.revision);
114556
+ return { revision };
114557
+ };
113765
114558
  }
113766
- var queues, lastCompletedAtByKey;
113767
- var init_workspace_sync_queue = __esm(() => {
113768
- queues = new Map;
113769
- lastCompletedAtByKey = new Map;
114559
+ var init_workspace_file_tree_checkpoint_send = __esm(() => {
114560
+ init_workspace_file_tree();
114561
+ init_api3();
114562
+ init_file_tree_data_hash();
114563
+ init_blob_snapshot_publish();
114564
+ init_sharded_snapshot_publish();
114565
+ });
114566
+
114567
+ // src/daemon/infrastructure/outbox/workspace-file-tree-delta-send.ts
114568
+ function toDeltaOperations(delta) {
114569
+ return [
114570
+ ...delta.added.map((entry) => ({
114571
+ o: "a",
114572
+ p: entry.path,
114573
+ e: entry.type === "directory" ? "d" : "f"
114574
+ })),
114575
+ ...delta.removed.map((entryPath) => ({
114576
+ o: "r",
114577
+ p: entryPath
114578
+ })),
114579
+ ...delta.typeChanged.map((entry) => ({
114580
+ o: "t",
114581
+ p: entry.path,
114582
+ e: entry.type === "directory" ? "d" : "f"
114583
+ }))
114584
+ ];
114585
+ }
114586
+ function createWorkspaceFileTreeDeltaSend(session2, normalizedWorkingDir) {
114587
+ return async (unit) => {
114588
+ const result = await session2.backend.mutation(api.workspaceFiles.applyFileTreeDeltaBatch, {
114589
+ sessionId: session2.sessionId,
114590
+ machineId: session2.machineId,
114591
+ workingDir: normalizedWorkingDir,
114592
+ operationId: unit.delta.operationId,
114593
+ baseRevision: unit.baseRevision,
114594
+ operations: toDeltaOperations(unit.delta)
114595
+ });
114596
+ if (result.status === "resync-required") {
114597
+ return { status: "conflict", revision: result.expectedRevision };
114598
+ }
114599
+ return result;
114600
+ };
114601
+ }
114602
+ var init_workspace_file_tree_delta_send = __esm(() => {
114603
+ init_api3();
113770
114604
  });
113771
114605
 
113772
114606
  // src/daemon/entry/files/file-tree-subscription.ts
113773
- import { randomUUID as randomUUID11 } from "node:crypto";
113774
114607
  function logSubscriptionWarn(label, err) {
113775
114608
  console.warn(`[${formatTimestamp()}] ⚠️ ${label}: ${getErrorMessage(err)}`);
113776
114609
  }
113777
- async function stopCoordinatorForWorkingDir(coordinators, normalized) {
114610
+ async function stopCoordinatorForWorkingDir(coordinators, checkpointOutboxRegistry, deltaOutboxRegistry, normalized) {
113778
114611
  const coordinatorPromise = coordinators.get(normalized);
113779
114612
  if (!coordinatorPromise)
113780
114613
  return;
@@ -113782,8 +114615,10 @@ async function stopCoordinatorForWorkingDir(coordinators, normalized) {
113782
114615
  await coordinatorPromise.then((coordinator2) => coordinator2.stop()).catch(() => {
113783
114616
  return;
113784
114617
  });
114618
+ await checkpointOutboxRegistry.stop(normalized);
114619
+ await deltaOutboxRegistry.stop(normalized);
113785
114620
  }
113786
- async function drainPendingFileTreeReleaseRequests(session2, coordinators) {
114621
+ async function drainPendingFileTreeReleaseRequests(session2, coordinators, checkpointOutboxRegistry, deltaOutboxRegistry) {
113787
114622
  const releases = await session2.backend.query(api.workspaceFiles.getPendingFileTreeReleaseRequests, {
113788
114623
  sessionId: session2.sessionId,
113789
114624
  machineId: session2.machineId
@@ -113795,7 +114630,7 @@ async function drainPendingFileTreeReleaseRequests(session2, coordinators) {
113795
114630
  releasesByDir.add(normalizeWorkingDirForLookup(release.workingDir));
113796
114631
  }
113797
114632
  for (const normalized of releasesByDir) {
113798
- await stopCoordinatorForWorkingDir(coordinators, normalized).then(() => session2.backend.mutation(api.workspaceFiles.fulfillFileTreeReleaseRequest, {
114633
+ await stopCoordinatorForWorkingDir(coordinators, checkpointOutboxRegistry, deltaOutboxRegistry, normalized).then(() => session2.backend.mutation(api.workspaceFiles.fulfillFileTreeReleaseRequest, {
113799
114634
  sessionId: session2.sessionId,
113800
114635
  machineId: session2.machineId,
113801
114636
  workingDir: normalized
@@ -113836,63 +114671,20 @@ async function drainPendingFileTreeRequests(session2, coordinators, ensureCoordi
113836
114671
  });
113837
114672
  await processPendingFileTreeRequests(session2, coordinators, ensureCoordinator, requests);
113838
114673
  }
113839
- async function syncScannedFileTree(session2, normalizedWorkingDir, tree, dataHash, syncGeneration) {
113840
- if (selectFileTreeSnapshotStrategyId(tree) === "sharded") {
113841
- const ref2 = await publishShardedSnapshot(session2, normalizedWorkingDir, tree, syncGeneration);
113842
- return { strategyId: ref2.strategyId, snapshotId: ref2.snapshotId };
113843
- }
113844
- const ref = await publishBlobSnapshot(session2, normalizedWorkingDir, buildBlobSnapshotPayload(tree, dataHash));
113845
- return { strategyId: ref.strategyId, snapshotId: ref.snapshotId };
113846
- }
113847
- function toDeltaOperations(delta) {
113848
- return [
113849
- ...delta.added.map((entry) => ({
113850
- o: "a",
113851
- p: entry.path,
113852
- e: entry.type === "directory" ? "d" : "f"
113853
- })),
113854
- ...delta.removed.map((entryPath) => ({
113855
- o: "r",
113856
- p: entryPath
113857
- })),
113858
- ...delta.typeChanged.map((entry) => ({
113859
- o: "t",
113860
- p: entry.path,
113861
- e: entry.type === "directory" ? "d" : "f"
113862
- }))
113863
- ];
113864
- }
113865
- async function publishCheckpoint(session2, normalizedWorkingDir, tree, revision) {
113866
- const dataHash = computeFileTreeDataHash(tree);
113867
- const syncGeneration = randomUUID11();
113868
- const snapshot = await syncScannedFileTree(session2, normalizedWorkingDir, tree, dataHash, syncGeneration);
113869
- let checkpointRevision = revision;
113870
- let result = await session2.backend.mutation(api.workspaceFiles.publishFileTreeCheckpoint, {
113871
- sessionId: session2.sessionId,
113872
- machineId: session2.machineId,
113873
- workingDir: normalizedWorkingDir,
113874
- revision: checkpointRevision,
113875
- ...snapshot
113876
- });
113877
- if (result.status === "resync-required") {
113878
- checkpointRevision = result.expectedRevision + 1;
113879
- result = await session2.backend.mutation(api.workspaceFiles.publishFileTreeCheckpoint, {
113880
- sessionId: session2.sessionId,
113881
- machineId: session2.machineId,
113882
- workingDir: normalizedWorkingDir,
113883
- revision: checkpointRevision,
113884
- ...snapshot
113885
- });
113886
- }
113887
- if (result.status === "snapshot-missing") {
113888
- throw new Error(`File tree checkpoint rejected: ${result.status}`);
113889
- }
113890
- console.log(`[${formatTimestamp()}] \uD83C\uDF33 File tree checkpoint: ${normalizedWorkingDir} (${tree.entries.length} entries, revision ${checkpointRevision})`);
113891
- return { revision: checkpointRevision };
113892
- }
113893
114674
  var startFileTreeSubscriptionEffect = () => exports_Effect.gen(function* () {
113894
114675
  const session2 = yield* DaemonSessionService;
113895
114676
  const coordinators = new Map;
114677
+ const checkpointOutboxRegistry = createWorkspaceFileTreeCheckpointOutboxRegistry(session2.machineId, (normalized) => {
114678
+ const send = createWorkspaceFileTreeCheckpointSend(session2, normalized);
114679
+ return async (state) => {
114680
+ const result = await send(state);
114681
+ console.log(`[${formatTimestamp()}] \uD83C\uDF33 File tree checkpoint: ${normalized} (${state.tree.entries.length} entries, revision ${result.revision})`);
114682
+ return result;
114683
+ };
114684
+ }, {
114685
+ onError: (normalized, error51) => logSubscriptionWarn(`File tree checkpoint outbox failed for ${normalized}`, error51)
114686
+ });
114687
+ const deltaOutboxRegistry = createWorkspaceFileTreeDeltaOutboxRegistry(session2.machineId, (normalized) => createWorkspaceFileTreeDeltaSend(session2, normalized));
113896
114688
  const ensureCoordinator = (workingDir, forceReconcile) => {
113897
114689
  const normalized = normalizeWorkingDirForLookup(workingDir);
113898
114690
  let coordinatorPromise = coordinators.get(normalized);
@@ -113900,23 +114692,8 @@ var startFileTreeSubscriptionEffect = () => exports_Effect.gen(function* () {
113900
114692
  coordinatorPromise = startWorkspaceFileTreeCoordinator({
113901
114693
  machineId: session2.machineId,
113902
114694
  workingDir: normalized,
113903
- onDelta: async (delta, baseRevision) => {
113904
- const operations = toDeltaOperations(delta);
113905
- const result = await session2.backend.mutation(api.workspaceFiles.applyFileTreeDeltaBatch, {
113906
- sessionId: session2.sessionId,
113907
- machineId: session2.machineId,
113908
- workingDir: normalized,
113909
- operationId: delta.operationId,
113910
- baseRevision,
113911
- operations
113912
- });
113913
- if (result.status === "resync-required") {
113914
- return { status: "conflict", revision: result.expectedRevision };
113915
- }
113916
- console.log(`[${formatTimestamp()}] \uD83C\uDF33 File tree delta: ${normalized} (${operations.length} operations, ${Buffer.byteLength(JSON.stringify(operations))} bytes, revision ${result.revision})`);
113917
- return result;
113918
- },
113919
- onCheckpoint: (tree, revision) => publishCheckpoint(session2, normalized, tree, revision),
114695
+ onDelta: (delta, baseRevision) => deltaOutboxRegistry.enqueue(normalized, { delta, baseRevision }),
114696
+ onCheckpoint: (tree, revision) => checkpointOutboxRegistry.enqueue(normalized, { tree, revision }),
113920
114697
  onError: (error51) => logSubscriptionWarn(`File tree coordinator failed for ${normalized}`, error51),
113921
114698
  onReconciled: (correctedPathCount) => {
113922
114699
  console.log(`[${formatTimestamp()}] \uD83C\uDF33 File tree reconciled: ${normalized} (${correctedPathCount} corrected paths)`);
@@ -113942,25 +114719,27 @@ var startFileTreeSubscriptionEffect = () => exports_Effect.gen(function* () {
113942
114719
  };
113943
114720
  return {
113944
114721
  drainPendingFileTreeRequests: () => drainPendingFileTreeRequests(session2, coordinators, ensureCoordinator),
113945
- drainPendingFileTreeReleaseRequests: () => drainPendingFileTreeReleaseRequests(session2, coordinators),
114722
+ drainPendingFileTreeReleaseRequests: () => drainPendingFileTreeReleaseRequests(session2, coordinators, checkpointOutboxRegistry, deltaOutboxRegistry),
113946
114723
  stop: () => {
113947
- Promise.all([...coordinators.values()].map((coordinator2) => coordinator2.then((handle) => handle.stop()).catch(() => {
113948
- return;
113949
- })));
113950
- coordinators.clear();
114724
+ (async () => {
114725
+ const keys3 = [...coordinators.keys()];
114726
+ await Promise.all(keys3.map((normalized) => stopCoordinatorForWorkingDir(coordinators, checkpointOutboxRegistry, deltaOutboxRegistry, normalized)));
114727
+ await deltaOutboxRegistry.stopAll();
114728
+ await checkpointOutboxRegistry.stopAll();
114729
+ coordinators.clear();
114730
+ })();
113951
114731
  }
113952
114732
  };
113953
114733
  });
113954
114734
  var init_file_tree_subscription = __esm(() => {
113955
- init_workspace_file_tree();
113956
114735
  init_esm();
113957
114736
  init_api3();
113958
- init_file_tree_data_hash();
113959
- init_blob_snapshot_publish();
113960
- init_sharded_snapshot_publish();
113961
114737
  init_workspace_file_tree_coordinator();
113962
114738
  init_workspace_sync_queue();
113963
114739
  init_convex_error();
114740
+ init_outbox();
114741
+ init_workspace_file_tree_checkpoint_send();
114742
+ init_workspace_file_tree_delta_send();
113964
114743
  init_daemon_services();
113965
114744
  });
113966
114745
 
@@ -114074,7 +114853,7 @@ var init_file_write_request_priority = __esm(() => {
114074
114853
 
114075
114854
  // src/daemon/entry/files/file-write-fulfillment.ts
114076
114855
  import { access as access4, mkdir as mkdir10, rename as rename4, rm as rm4, writeFile as writeFile9 } from "node:fs/promises";
114077
- import { dirname as dirname12 } from "node:path";
114856
+ import { dirname as dirname14 } from "node:path";
114078
114857
  function isTerminalFileWriteError(errorMessage) {
114079
114858
  const terminalMessages = new Set([
114080
114859
  "Invalid file path",
@@ -114173,7 +114952,7 @@ async function validateWriteOperation(operation, absolutePath) {
114173
114952
  }
114174
114953
  async function writePayloadToDisk(absolutePath, operation, content) {
114175
114954
  if (operation === "create") {
114176
- await mkdir10(dirname12(absolutePath), { recursive: true });
114955
+ await mkdir10(dirname14(absolutePath), { recursive: true });
114177
114956
  await writeFile9(absolutePath, content, { flag: "wx" });
114178
114957
  return;
114179
114958
  }
@@ -114251,7 +115030,7 @@ async function fulfillOneFileWriteRequest(session2, request2) {
114251
115030
  });
114252
115031
  return;
114253
115032
  }
114254
- await mkdir10(dirname12(targetResolved.absolutePath), { recursive: true });
115033
+ await mkdir10(dirname14(targetResolved.absolutePath), { recursive: true });
114255
115034
  await rename4(resolved.absolutePath, targetResolved.absolutePath);
114256
115035
  await completeWriteRequest(session2, claimed._id, claimed.revision, { status: "done" });
114257
115036
  const elapsed4 = Date.now() - startTime;
@@ -116551,10 +117330,10 @@ var init_deps = __esm(() => {
116551
117330
  });
116552
117331
 
116553
117332
  // src/daemon/entry/persistence-path.ts
116554
- import { homedir as homedir8 } from "node:os";
116555
- import { join as join25 } from "node:path";
117333
+ import { homedir as homedir10 } from "node:os";
117334
+ import { join as join26 } from "node:path";
116556
117335
  function resolvePersistenceDbPath(machineId) {
116557
- return join25(homedir8(), ".chatroom", "daemon", machineId, "events.sqlite");
117336
+ return join26(homedir10(), ".chatroom", "daemon", machineId, "events.sqlite");
116558
117337
  }
116559
117338
  var init_persistence_path = () => {};
116560
117339
 
@@ -117590,10 +118369,10 @@ function resolveEnvSlug(convexUrl) {
117590
118369
  }
117591
118370
 
117592
118371
  // src/infrastructure/log-server/resolve-logs-db-path.ts
117593
- import { homedir as homedir9 } from "node:os";
117594
- import { join as join26 } from "node:path";
118372
+ import { homedir as homedir11 } from "node:os";
118373
+ import { join as join27 } from "node:path";
117595
118374
  function resolveLogsDbPath(convexUrl) {
117596
- return join26(homedir9(), ".chatroom", resolveEnvSlug(convexUrl ?? getConvexUrl()), "logs.sqlite");
118375
+ return join27(homedir11(), ".chatroom", resolveEnvSlug(convexUrl ?? getConvexUrl()), "logs.sqlite");
117597
118376
  }
117598
118377
  var init_resolve_logs_db_path = __esm(() => {
117599
118378
  init_client2();
@@ -117626,12 +118405,12 @@ var init_log_schema = __esm(() => {
117626
118405
  });
117627
118406
 
117628
118407
  // src/infrastructure/log-server/open-log-database.ts
117629
- import { mkdirSync as mkdirSync6 } from "node:fs";
117630
- import { dirname as dirname13 } from "node:path";
117631
- import { DatabaseSync } from "node:sqlite";
118408
+ import { mkdirSync as mkdirSync8 } from "node:fs";
118409
+ import { dirname as dirname15 } from "node:path";
118410
+ import { DatabaseSync as DatabaseSync3 } from "node:sqlite";
117632
118411
  function openLogDatabase(dbPath) {
117633
- mkdirSync6(dirname13(dbPath), { recursive: true });
117634
- const db = new DatabaseSync(dbPath);
118412
+ mkdirSync8(dirname15(dbPath), { recursive: true });
118413
+ const db = new DatabaseSync3(dbPath);
117635
118414
  db.exec("PRAGMA journal_mode = WAL");
117636
118415
  db.exec("PRAGMA busy_timeout = 5000");
117637
118416
  db.exec("PRAGMA synchronous = NORMAL");
@@ -117857,12 +118636,12 @@ var init_schema = __esm(() => {
117857
118636
  });
117858
118637
 
117859
118638
  // src/daemon/infrastructure/persistence/open-database.ts
117860
- import { mkdirSync as mkdirSync7 } from "node:fs";
117861
- import { dirname as dirname14 } from "node:path";
117862
- import { DatabaseSync as DatabaseSync2 } from "node:sqlite";
118639
+ import { mkdirSync as mkdirSync9 } from "node:fs";
118640
+ import { dirname as dirname16 } from "node:path";
118641
+ import { DatabaseSync as DatabaseSync4 } from "node:sqlite";
117863
118642
  function openDatabase(dbPath) {
117864
- mkdirSync7(dirname14(dbPath), { recursive: true });
117865
- const db = new DatabaseSync2(dbPath);
118643
+ mkdirSync9(dirname16(dbPath), { recursive: true });
118644
+ const db = new DatabaseSync4(dbPath);
117866
118645
  for (const sql of MIGRATIONS2) {
117867
118646
  db.exec(sql);
117868
118647
  }
@@ -131572,19 +132351,19 @@ function routeRequest(req, res, deps) {
131572
132351
 
131573
132352
  // src/daemon/local-web/server/serve-static.ts
131574
132353
  import { existsSync as existsSync10, readFileSync as readFileSync11 } from "node:fs";
131575
- import { dirname as dirname15, join as join27 } from "node:path";
132354
+ import { dirname as dirname17, join as join28 } from "node:path";
131576
132355
  import { fileURLToPath as fileURLToPath7 } from "node:url";
131577
132356
  function clientDistCandidates(here) {
131578
132357
  return [
131579
- join27(here, "client/build"),
131580
- join27(here, "../client/build"),
131581
- join27(here, "../src/daemon/local-web/client/build")
132358
+ join28(here, "client/build"),
132359
+ join28(here, "../client/build"),
132360
+ join28(here, "../src/daemon/local-web/client/build")
131582
132361
  ];
131583
132362
  }
131584
- function resolveClientDistDir(here = dirname15(fileURLToPath7(import.meta.url))) {
132363
+ function resolveClientDistDir(here = dirname17(fileURLToPath7(import.meta.url))) {
131585
132364
  const candidates = clientDistCandidates(here);
131586
132365
  for (const dir of candidates) {
131587
- if (existsSync10(join27(dir, "index.html")))
132366
+ if (existsSync10(join28(dir, "index.html")))
131588
132367
  return dir;
131589
132368
  }
131590
132369
  return candidates[0];
@@ -131597,7 +132376,7 @@ function tryServeStatic(req, res, distDir) {
131597
132376
  return false;
131598
132377
  }
131599
132378
  const safePath = pathname === "/" ? "/index.html" : pathname;
131600
- const filePath = join27(distDir, safePath);
132379
+ const filePath = join28(distDir, safePath);
131601
132380
  if (!filePath.startsWith(distDir)) {
131602
132381
  res.writeHead(403);
131603
132382
  res.end();
@@ -131614,7 +132393,7 @@ function tryServeStatic(req, res, distDir) {
131614
132393
  }
131615
132394
  return true;
131616
132395
  }
131617
- const indexPath = join27(distDir, "index.html");
132396
+ const indexPath = join28(distDir, "index.html");
131618
132397
  if (existsSync10(indexPath)) {
131619
132398
  res.writeHead(200, { "Content-Type": "text/html" });
131620
132399
  if (req.method === "HEAD") {
@@ -133345,4 +134124,4 @@ program2.hook("preAction", async (_thisCommand, actionCommand) => {
133345
134124
  });
133346
134125
  program2.parse();
133347
134126
 
133348
- //# debugId=FF157482FA3E83C464756E2164756E21
134127
+ //# debugId=6381A1F83F16A2C964756E2164756E21