@karmaniverous/jeeves-watcher 0.17.10 → 0.18.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.
@@ -1,8 +1,8 @@
1
1
  #!/usr/bin/env node
2
- import { DEFAULT_PORTS, postJson, fetchJson, getPackageVersion, createServiceCli } from '@karmaniverous/jeeves';
2
+ import { substituteEnvVars, DEFAULT_PORTS, postJson, fetchJson, getPackageVersion, createServiceCli } from '@karmaniverous/jeeves';
3
3
  import { dirname, resolve, join, relative } from 'node:path';
4
4
  import { fileURLToPath } from 'node:url';
5
- import { jeevesWatcherConfigSchema, LOGGING_DEFAULTS, API_DEFAULTS, EMBEDDING_DEFAULTS, CONFIG_WATCH_DEFAULTS, WATCH_DEFAULTS, ROOT_DEFAULTS, INIT_CONFIG_TEMPLATE, DEFAULT_PORT as DEFAULT_PORT$1, PLUGIN_PACKAGE, SERVICE_PACKAGE, COMPONENT_NAME } from '@karmaniverous/jeeves-watcher-core';
5
+ import { jeevesWatcherConfigSchema, LOGGING_DEFAULTS, API_DEFAULTS, EMBEDDING_DEFAULTS, CONFIG_WATCH_DEFAULTS, WATCH_DEFAULTS, ROOT_DEFAULTS, extractWatchPathStrings, INIT_CONFIG_TEMPLATE, DEFAULT_PORT as DEFAULT_PORT$1, PLUGIN_PACKAGE, SERVICE_PACKAGE, COMPONENT_NAME } from '@karmaniverous/jeeves-watcher-core';
6
6
  import { packageDirectorySync } from 'package-directory';
7
7
  import { readFileSync, existsSync, mkdirSync, renameSync, statSync, readdirSync } from 'node:fs';
8
8
  import { cosmiconfig } from 'cosmiconfig';
@@ -42,49 +42,6 @@ function mergeInferenceRules(existing, incoming) {
42
42
  return merged;
43
43
  }
44
44
 
45
- /**
46
- * @module config/substituteEnvVars
47
- *
48
- * Deep-walks config objects and replaces `${VAR_NAME}` patterns with environment variable values.
49
- */
50
- const ENV_PATTERN = /\$\{([^}]+)\}/g;
51
- /**
52
- * Replace `${VAR_NAME}` patterns in a string with `process.env.VAR_NAME`.
53
- *
54
- * @param value - The string to process.
55
- * @returns The string with resolved env vars; unresolvable expressions left untouched.
56
- */
57
- function substituteString(value) {
58
- return value.replace(ENV_PATTERN, (match, varName) => {
59
- const envValue = process.env[varName];
60
- if (envValue === undefined)
61
- return match;
62
- return envValue;
63
- });
64
- }
65
- /**
66
- * Deep-walk a value and substitute `${VAR_NAME}` patterns in all string values.
67
- *
68
- * @param value - The value to walk (object, array, or primitive).
69
- * @returns A new value with all env var references resolved.
70
- */
71
- function substituteEnvVars(value) {
72
- if (typeof value === 'string') {
73
- return substituteString(value);
74
- }
75
- if (Array.isArray(value)) {
76
- return value.map((item) => substituteEnvVars(item));
77
- }
78
- if (value !== null && typeof value === 'object') {
79
- const result = {};
80
- for (const [key, val] of Object.entries(value)) {
81
- result[key] = substituteEnvVars(val);
82
- }
83
- return result;
84
- }
85
- return value;
86
- }
87
-
88
45
  const MODULE_NAME = 'jeeves-watcher';
89
46
  /**
90
47
  * Merge sensible defaults into a loaded configuration.
@@ -267,7 +224,7 @@ async function startFromConfig(configPath, descriptor) {
267
224
  const config = await loadConfig(resolvedPath);
268
225
  // Dynamic import breaks the circular dependency between this module
269
226
  // and app/index.ts (which defines JeevesWatcher and re-exports startFromConfig).
270
- const { JeevesWatcher } = await import('./index-07J6R3B8.js');
227
+ const { JeevesWatcher } = await import('./index-DtyqhT2s.js');
271
228
  const app = new JeevesWatcher(config, resolvedPath, descriptor);
272
229
  installShutdownHandlers(() => app.stop());
273
230
  await app.start();
@@ -545,11 +502,12 @@ function normalizeSlashes(path) {
545
502
  */
546
503
  function isPathWatched(filePath, watchPaths, ignoredPaths) {
547
504
  const normalised = normalizeSlashes(filePath);
548
- const isIncluded = picomatch(watchPaths, { dot: true });
505
+ const opts = { dot: true, nocase: process.platform === 'win32' };
506
+ const isIncluded = picomatch(watchPaths, opts);
549
507
  if (!isIncluded(normalised))
550
508
  return false;
551
509
  if (ignoredPaths && ignoredPaths.length > 0) {
552
- const isExcluded = picomatch(ignoredPaths, { dot: true });
510
+ const isExcluded = picomatch(ignoredPaths, opts);
553
511
  if (isExcluded(normalised))
554
512
  return false;
555
513
  }
@@ -933,7 +891,7 @@ async function computePrunePlan(deps) {
933
891
  continue;
934
892
  }
935
893
  seenFiles.add(filePath);
936
- const watched = isPathWatched(filePath, config.watch.paths, config.watch.ignored);
894
+ const watched = isPathWatched(filePath, extractWatchPathStrings(config.watch.paths), config.watch.ignored);
937
895
  const gitignored = gitignoreFilter
938
896
  ? gitignoreFilter.isIgnored(filePath)
939
897
  : false;
@@ -953,7 +911,7 @@ async function computePrunePlan(deps) {
953
911
  incomplete = true;
954
912
  }
955
913
  const orphanedFileList = [...orphanedFiles];
956
- const byRoot = groupByRoot(orphanedFileList, config.watch.paths);
914
+ const byRoot = groupByRoot(orphanedFileList, extractWatchPathStrings(config.watch.paths));
957
915
  return {
958
916
  plan: {
959
917
  total: totalPoints,
@@ -1069,18 +1027,18 @@ async function executeReindex(deps, scope, path, dryRun = false) {
1069
1027
  }
1070
1028
  else if (scope === 'rules' && pathArray && pathArray.length > 0) {
1071
1029
  // Rules scope with path filter: list from watch roots intersected with caller globs
1072
- fileList = await listFilesFromWatchRoots(config.watch.paths, config.watch.ignored, pathArray, isGitignored);
1030
+ fileList = await listFilesFromWatchRoots(extractWatchPathStrings(config.watch.paths), config.watch.ignored, pathArray, isGitignored);
1073
1031
  }
1074
1032
  else {
1075
1033
  // rules or full: list files from globs
1076
- fileList = await listFilesFromGlobs(config.watch.paths, config.watch.ignored, isGitignored);
1034
+ fileList = await listFilesFromGlobs(extractWatchPathStrings(config.watch.paths), config.watch.ignored, isGitignored);
1077
1035
  }
1078
1036
  if (fileList !== undefined) {
1079
1037
  plan = {
1080
1038
  total: fileList.length,
1081
1039
  toProcess: fileList.length,
1082
1040
  toDelete: 0,
1083
- byRoot: groupByRoot(fileList, config.watch.paths),
1041
+ byRoot: groupByRoot(fileList, extractWatchPathStrings(config.watch.paths)),
1084
1042
  };
1085
1043
  }
1086
1044
  if (dryRun) {
@@ -1091,7 +1049,7 @@ async function executeReindex(deps, scope, path, dryRun = false) {
1091
1049
  total: pathFiles.length,
1092
1050
  toProcess: pathFiles.length,
1093
1051
  toDelete: 0,
1094
- byRoot: groupByRoot(pathFiles, config.watch.paths),
1052
+ byRoot: groupByRoot(pathFiles, extractWatchPathStrings(config.watch.paths)),
1095
1053
  };
1096
1054
  }
1097
1055
  return { filesProcessed: 0, durationMs: 0, errors: 0, plan };
@@ -1118,7 +1076,7 @@ async function executeReindex(deps, scope, path, dryRun = false) {
1118
1076
  });
1119
1077
  }
1120
1078
  else if (scope === 'rules') {
1121
- filesProcessed = await processAllFiles(config.watch.paths, config.watch.ignored, processor, 'processRulesUpdate', concurrency, {
1079
+ filesProcessed = await processAllFiles(extractWatchPathStrings(config.watch.paths), config.watch.ignored, processor, 'processRulesUpdate', concurrency, {
1122
1080
  onTotal: (total) => reindexTracker?.setTotal(total),
1123
1081
  onFileProcessed: () => reindexTracker?.incrementProcessed(),
1124
1082
  }, isGitignored, fileList);
@@ -1129,7 +1087,7 @@ async function executeReindex(deps, scope, path, dryRun = false) {
1129
1087
  total: uniqueFiles.length,
1130
1088
  toProcess: uniqueFiles.length,
1131
1089
  toDelete: 0,
1132
- byRoot: groupByRoot(uniqueFiles, config.watch.paths),
1090
+ byRoot: groupByRoot(uniqueFiles, extractWatchPathStrings(config.watch.paths)),
1133
1091
  };
1134
1092
  reindexTracker?.setTotal(uniqueFiles.length);
1135
1093
  await parallel(concurrency, uniqueFiles, async (filePath) => {
@@ -1140,7 +1098,7 @@ async function executeReindex(deps, scope, path, dryRun = false) {
1140
1098
  }
1141
1099
  else {
1142
1100
  // Full reindex
1143
- filesProcessed = await processAllFiles(config.watch.paths, config.watch.ignored, processor, 'processFile', concurrency, {
1101
+ filesProcessed = await processAllFiles(extractWatchPathStrings(config.watch.paths), config.watch.ignored, processor, 'processFile', concurrency, {
1144
1102
  onTotal: (total) => reindexTracker?.setTotal(total),
1145
1103
  onFileProcessed: () => reindexTracker?.incrementProcessed(),
1146
1104
  }, isGitignored, fileList);
@@ -1188,7 +1146,7 @@ async function collectPathFiles(pathArray, config, gitignoreFilter) {
1188
1146
  * Get the file list for a path-scoped reindex (for plan computation).
1189
1147
  */
1190
1148
  async function getPathFileList(targetPath, config, gitignoreFilter) {
1191
- const watched = isPathWatched(targetPath, config.watch.paths, config.watch.ignored);
1149
+ const watched = isPathWatched(targetPath, extractWatchPathStrings(config.watch.paths), config.watch.ignored);
1192
1150
  if (!watched) {
1193
1151
  throw new Error(`Path is outside watch scope: ${targetPath}`);
1194
1152
  }
@@ -1200,7 +1158,7 @@ async function getPathFileList(targetPath, config, gitignoreFilter) {
1200
1158
  return [targetPath];
1201
1159
  if (stats.isDirectory()) {
1202
1160
  const isGitignored = createIsGitignored(gitignoreFilter);
1203
- const allWatchedFiles = await listFilesFromGlobs(config.watch.paths, config.watch.ignored, isGitignored);
1161
+ const allWatchedFiles = await listFilesFromGlobs(extractWatchPathStrings(config.watch.paths), config.watch.ignored, isGitignored);
1204
1162
  const targetAbsPath = resolve(targetPath);
1205
1163
  return allWatchedFiles.filter((f) => resolve(f).startsWith(targetAbsPath));
1206
1164
  }
@@ -1498,4 +1456,4 @@ const watcherDescriptor = {
1498
1456
  const program = createServiceCli(watcherDescriptor);
1499
1457
  program.parse();
1500
1458
 
1501
- export { CONFIG_WATCH_VALID_SCOPES as C, GitignoreFilter as G, VALID_REINDEX_SCOPES as V, normalizeError as a, startFromConfig as b, executeReindex as e, getWatchRootBases as g, isPathWatched as i, loadConfig as l, mergeInferenceRules as m, normalizeSlashes as n, retry as r, sleep as s };
1459
+ export { CONFIG_WATCH_VALID_SCOPES as C, GitignoreFilter as G, VALID_REINDEX_SCOPES as V, normalizeSlashes as a, startFromConfig as b, executeReindex as e, getWatchRootBases as g, isPathWatched as i, loadConfig as l, mergeInferenceRules as m, normalizeError as n, retry as r, sleep as s };
package/dist/index.d.ts CHANGED
@@ -1,7 +1,7 @@
1
1
  import { JeevesComponentDescriptor } from '@karmaniverous/jeeves';
2
2
  import { FastifyInstance } from 'fastify';
3
3
  import pino from 'pino';
4
- import { EmbeddingConfig, InferenceRule, SchemaEntry, VectorStoreConfig, WatchConfig, JeevesWatcherConfig, LoggingConfig } from '@karmaniverous/jeeves-watcher-core';
4
+ import { EmbeddingConfig, InferenceRule, SchemaEntry, VectorStoreConfig, VcsConfig, JeevesWatcherConfig, WatchConfig, LoggingConfig, VcsRetentionConfig } from '@karmaniverous/jeeves-watcher-core';
5
5
  export { ApiConfig, ConfigWatchConfig, EmbeddingConfig, InferenceRule, JeevesWatcherConfig, JeevesWatcherConfigInput, LoggingConfig, VectorStoreConfig, WatchConfig, apiConfigSchema, configWatchConfigSchema, embeddingConfigSchema, inferenceRuleSchema, jeevesWatcherConfigSchema, loggingConfigSchema, vectorStoreConfigSchema, watchConfigSchema } from '@karmaniverous/jeeves-watcher-core';
6
6
  import { z } from 'zod';
7
7
  import Handlebars from 'handlebars';
@@ -783,9 +783,10 @@ interface VectorStore {
783
783
  * @param limit - Maximum results to return.
784
784
  * @param textWeight - Weight for text results in RRF (0–1).
785
785
  * @param filter - Optional Qdrant filter.
786
+ * @param offset - Optional result offset for pagination.
786
787
  * @returns An array of search results.
787
788
  */
788
- hybridSearch(vector: number[], queryText: string, limit: number, textWeight: number, filter?: Record<string, unknown>): Promise<SearchResult[]>;
789
+ hybridSearch(vector: number[], queryText: string, limit: number, textWeight: number, filter?: Record<string, unknown>, offset?: number): Promise<SearchResult[]>;
789
790
  /**
790
791
  * Retrieve points with their vectors by ID.
791
792
  *
@@ -908,9 +909,10 @@ declare class VectorStoreClient implements VectorStore {
908
909
  * @param limit - Maximum results to return.
909
910
  * @param textWeight - Weight for text results in RRF (0–1).
910
911
  * @param filter - Optional Qdrant filter.
912
+ * @param offset - Optional result offset for pagination.
911
913
  * @returns An array of search results.
912
914
  */
913
- hybridSearch(vector: number[], queryText: string, limit: number, textWeight: number, filter?: Record<string, unknown>): Promise<SearchResult[]>;
915
+ hybridSearch(vector: number[], queryText: string, limit: number, textWeight: number, filter?: Record<string, unknown>, offset?: number): Promise<SearchResult[]>;
914
916
  /**
915
917
  * Retrieve points with their vectors by ID.
916
918
  *
@@ -1225,6 +1227,192 @@ declare class EventQueue {
1225
1227
  private maybeResolveIdleWorkers;
1226
1228
  }
1227
1229
 
1230
+ /**
1231
+ * @module vcs/CommitMessageGenerator
1232
+ * Generates AI-powered commit messages via the Anthropic Messages API.
1233
+ */
1234
+
1235
+ /**
1236
+ * Generates AI commit messages using the Anthropic Messages API.
1237
+ */
1238
+ declare class CommitMessageGenerator {
1239
+ private readonly provider;
1240
+ private readonly model;
1241
+ private readonly apiKey;
1242
+ private readonly logger;
1243
+ constructor(provider: string, model: string, apiKey: string | undefined, logger: pino.Logger);
1244
+ /**
1245
+ * Generate a commit message from file changes.
1246
+ *
1247
+ * @param files - List of changed file paths.
1248
+ * @param diffSummary - Combined diff output (stat + patch).
1249
+ * @returns A one-line commit message, or null on failure.
1250
+ */
1251
+ generate(files: string[], diffSummary: string): Promise<string | null>;
1252
+ }
1253
+
1254
+ /**
1255
+ * @module vcs/VcsManager
1256
+ * Per-root VCS manager for git-backed content versioning.
1257
+ */
1258
+
1259
+ /** Metadata for a pending reversion to include in the commit message. */
1260
+ interface PendingReversion {
1261
+ glob: string;
1262
+ commit: string;
1263
+ paths: string[];
1264
+ }
1265
+ /** Push error record for status reporting. */
1266
+ interface PushError {
1267
+ timestamp: string;
1268
+ message: string;
1269
+ }
1270
+ /**
1271
+ * Per-root VCS manager for git-backed content versioning.
1272
+ *
1273
+ * Each VCS-enabled watch root gets its own VcsManager instance, which owns
1274
+ * a debounced commit pipeline: file changes are batched, staged, committed
1275
+ * (with optional AI-generated messages), and optionally pushed to a remote.
1276
+ *
1277
+ * Concurrency: only one commit is in-flight at a time per root. Index.lock
1278
+ * contention is handled with exponential backoff retries (D10).
1279
+ */
1280
+ declare class VcsManager {
1281
+ readonly config: VcsConfig;
1282
+ readonly rootPath: string;
1283
+ readonly remoteUrl: string | undefined;
1284
+ private readonly accessToken;
1285
+ private readonly logger;
1286
+ private readonly commitMessageGenerator;
1287
+ private readonly pending;
1288
+ private readonly pendingReversions;
1289
+ private readonly _pushErrors;
1290
+ private readonly squashManager;
1291
+ private debounceTimer;
1292
+ private commitInFlight;
1293
+ private started;
1294
+ private _lastPushTime;
1295
+ constructor(rootPath: string, config: VcsConfig, logger: pino.Logger, commitMessageGenerator?: CommitMessageGenerator, remoteUrl?: string, accessToken?: string);
1296
+ get lastPushTime(): string | null;
1297
+ get pushErrors(): readonly PushError[];
1298
+ /**
1299
+ * Begin accepting file changes. Sets up the debounce mechanism.
1300
+ */
1301
+ start(): void;
1302
+ /**
1303
+ * Add a file to the pending set and reset the debounce timer.
1304
+ * If the pending set exceeds maxBatchSize, flush immediately.
1305
+ *
1306
+ * @param filePath - Absolute path of the changed file.
1307
+ */
1308
+ fileChanged(filePath: string): void;
1309
+ /**
1310
+ * Record reversion metadata so the next commit uses a revert-prefixed message.
1311
+ *
1312
+ * @param reversion - The reversion metadata to record.
1313
+ */
1314
+ addPendingReversion(reversion: PendingReversion): void;
1315
+ /**
1316
+ * Stage a file deletion and add to pending set.
1317
+ * git add handles deleted files when the file is gone from disk.
1318
+ *
1319
+ * @param filePath - Absolute path of the deleted file.
1320
+ */
1321
+ handleUnlink(filePath: string): void;
1322
+ /**
1323
+ * Flush all pending files immediately.
1324
+ */
1325
+ flush(): Promise<void>;
1326
+ /**
1327
+ * Stop accepting file changes, flush pending, and clean up timers.
1328
+ */
1329
+ stop(): Promise<void>;
1330
+ /**
1331
+ * Take up to N items from the pending set.
1332
+ */
1333
+ private takeBatch;
1334
+ /**
1335
+ * Clear the debounce timer.
1336
+ */
1337
+ private clearDebounce;
1338
+ /**
1339
+ * Reset the debounce timer to fire flush() after commitDebounceMs.
1340
+ */
1341
+ private resetDebounce;
1342
+ /**
1343
+ * Get the cached diff for staged files, for AI context.
1344
+ */
1345
+ private getStagedDiff;
1346
+ /**
1347
+ * Build the template commit message (no AI).
1348
+ */
1349
+ private buildTemplateMessage;
1350
+ /**
1351
+ * Build the commit message, using AI when available with template fallback.
1352
+ */
1353
+ private buildCommitMessage;
1354
+ /**
1355
+ * Commit a batch of files to the git repo with index.lock retry.
1356
+ */
1357
+ private commitBatch;
1358
+ /**
1359
+ * Push to the configured remote if remoteUrl is set.
1360
+ * On failure: logs the error and records it in pushErrors; never throws.
1361
+ */
1362
+ private pushIfConfigured;
1363
+ }
1364
+
1365
+ /**
1366
+ * @module vcs/VcsCoordinator
1367
+ * Orchestrates VCS across all watch roots. Routes file events to the correct
1368
+ * root's VcsManager instance.
1369
+ */
1370
+
1371
+ /**
1372
+ * Orchestrates VCS across all VCS-enabled watch roots.
1373
+ */
1374
+ declare class VcsCoordinator {
1375
+ private readonly managers;
1376
+ private readonly roots;
1377
+ private readonly logger;
1378
+ constructor(config: JeevesWatcherConfig, logger: pino.Logger);
1379
+ /**
1380
+ * Start all VcsManager instances.
1381
+ */
1382
+ start(): void;
1383
+ /**
1384
+ * Route a file event to the correct root's VcsManager.
1385
+ *
1386
+ * @param filePath - Absolute path of the changed file.
1387
+ * @param event - The event type: add, change, or unlink.
1388
+ */
1389
+ onFileChange(filePath: string, event: 'add' | 'change' | 'unlink'): void;
1390
+ /**
1391
+ * Flush all managers and clean up.
1392
+ */
1393
+ stop(): Promise<void>;
1394
+ /**
1395
+ * Get the sorted root paths (longest-first).
1396
+ */
1397
+ getRoots(): readonly string[];
1398
+ /**
1399
+ * Get the VcsManager for a specific root path.
1400
+ */
1401
+ getManager(root: string): VcsManager | undefined;
1402
+ /**
1403
+ * Get all managers as [root, manager] pairs.
1404
+ */
1405
+ getAllManagers(): ReadonlyMap<string, VcsManager>;
1406
+ /**
1407
+ * Find the VcsManager that owns the given normalized file path.
1408
+ * Uses longest-prefix-match against resolved watch roots.
1409
+ *
1410
+ * @param normalizedPath - Normalized absolute path (forward slashes).
1411
+ * @returns The matching VcsManager, or undefined.
1412
+ */
1413
+ findManagerForPath(normalizedPath: string): VcsManager | undefined;
1414
+ }
1415
+
1228
1416
  /**
1229
1417
  * @module api/InitialScanTracker
1230
1418
  * Tracks initial filesystem scan state for status reporting.
@@ -1342,6 +1530,8 @@ interface FileSystemWatcherOptions {
1342
1530
  initialScanTracker?: InitialScanTracker;
1343
1531
  /** Optional content hash cache for move detection. */
1344
1532
  contentHashCache?: ContentHashCache;
1533
+ /** Optional callback for VCS file change notifications. */
1534
+ onVcsFileChange?: (filePath: string, event: 'add' | 'change' | 'unlink') => void;
1345
1535
  }
1346
1536
  /**
1347
1537
  * Filesystem watcher that maps chokidar events to the processing queue.
@@ -1355,6 +1545,7 @@ declare class FileSystemWatcher {
1355
1545
  private readonly gitignoreFilter?;
1356
1546
  private readonly initialScanTracker?;
1357
1547
  private readonly contentHashCache?;
1548
+ private readonly onVcsFileChange?;
1358
1549
  private moveCorrelator?;
1359
1550
  private globMatches;
1360
1551
  private watcher;
@@ -1494,6 +1685,8 @@ interface ApiServerOptions {
1494
1685
  getFileSystemWatcher?: () => FileSystemWatcher | undefined;
1495
1686
  /** Optional enrichment store for persisted enrichment metadata. */
1496
1687
  enrichmentStore?: EnrichmentStoreInterface;
1688
+ /** VCS coordinator for git-backed versioning API routes. */
1689
+ vcsCoordinator?: VcsCoordinator;
1497
1690
  }
1498
1691
  /**
1499
1692
  * Create the Fastify API server with all routes registered.
@@ -1599,6 +1792,7 @@ declare class JeevesWatcher {
1599
1792
  private gitignoreFilter;
1600
1793
  private enrichmentStore;
1601
1794
  private contentHashCache;
1795
+ private vcsCoordinator;
1602
1796
  private readonly initialScanTracker;
1603
1797
  private readonly version;
1604
1798
  /** Create a new JeevesWatcher instance. */
@@ -1683,5 +1877,91 @@ declare function contentHash(text: string): string;
1683
1877
  */
1684
1878
  declare function pointId(filePath: string, chunkIndex?: number): string;
1685
1879
 
1686
- export { ContentHashCache, DocumentProcessor, EnrichmentStore, EventQueue, FileSystemWatcher, GitignoreFilter, InitialScanTracker, IssuesManager, JeevesWatcher, ReindexTracker, SystemHealth, TemplateEngine, ValuesManager, VectorStoreClient, VirtualRuleStore, applyRules, buildAttributes, buildTemplateEngine, compileRules, contentHash, createApiServer, createEmbeddingProvider, createHandlebarsInstance, createLogger, extractText, issueRecordSchema, loadConfig, loadCustomHelpers, mergeEnrichment, pointId, registerBuiltinHelpers, resolveTemplateSource, startFromConfig, watcherDescriptor };
1687
- export type { AllHelpersIntrospection, ApiServerOptions, ApplyRulesOptions, ApplyRulesResult, CollectionInfo, CompiledRule, CompiledTemplate, DocumentProcessorDeps, DocumentProcessorInterface, EmbeddingProvider, EnrichmentStoreInterface, EventQueueOptions, ExtractedText, Extractor, FileAttributes, FileSystemWatcherOptions, HelperModuleIntrospection, InitialScanStatus, IssueRecord, IssuesFile, JeevesWatcherFactories, JeevesWatcherRuntimeOptions, PayloadFieldSchema, ProcessFn, ProcessorConfig, ProviderFactory, ReindexStatus, RenderResult, RuleLogger, ScrollPageResult, ScrolledPoint, SearchResult, SystemHealthOptions, ValuesIndex, VectorPoint, VectorStore, WatchEvent };
1880
+ /**
1881
+ * @module vcs/resolveWatchRoot
1882
+ * Resolves which VCS-enabled watch root(s) own a given absolute path or glob.
1883
+ */
1884
+
1885
+ /** Result of resolving a path to its watch root. */
1886
+ interface ResolvedWatchRoot {
1887
+ /** Absolute root path (normalized forward slashes). */
1888
+ root: string;
1889
+ /** Path relative to the root. */
1890
+ relativePath: string;
1891
+ }
1892
+
1893
+ /**
1894
+ * @module vcs/SquashManager
1895
+ * Handles scheduled squash retention for git-backed VCS roots.
1896
+ */
1897
+
1898
+ /** Result of a squash operation. */
1899
+ interface SquashResult {
1900
+ squashed: boolean;
1901
+ commitsRemoved?: number;
1902
+ commitsRetained?: number;
1903
+ error?: string;
1904
+ }
1905
+ /** Commit metadata for retention calculation. */
1906
+ interface CommitInfo {
1907
+ hash: string;
1908
+ date: Date;
1909
+ }
1910
+ /**
1911
+ * Manages scheduled squash retention for a single VCS root.
1912
+ *
1913
+ * Runs on a cron schedule (checked every 60s). When triggered, squashes
1914
+ * commits older than the retention boundary (the tighter of maxAgeDays
1915
+ * and maxVersions) into a single "historical baseline" orphan commit,
1916
+ * then cherry-picks retained commits on top. Force-pushes to remote
1917
+ * if configured (D13).
1918
+ */
1919
+ declare class SquashManager {
1920
+ private readonly rootPath;
1921
+ private readonly retention;
1922
+ private readonly remoteUrl;
1923
+ private readonly accessToken;
1924
+ private readonly logger;
1925
+ private intervalTimer;
1926
+ private running;
1927
+ constructor(rootPath: string, retention: VcsRetentionConfig, logger: pino.Logger, remoteUrl?: string, accessToken?: string);
1928
+ /**
1929
+ * Start the cron-based squash scheduler.
1930
+ * Checks every 60 seconds if the cron expression matches.
1931
+ */
1932
+ start(): void;
1933
+ /**
1934
+ * Stop the cron scheduler.
1935
+ */
1936
+ stop(): void;
1937
+ /**
1938
+ * Run the squash operation. Exposed publicly for testing.
1939
+ */
1940
+ runSquash(): Promise<SquashResult>;
1941
+ /**
1942
+ * Get all commits in chronological order (oldest first).
1943
+ */
1944
+ getCommitLog(): Promise<CommitInfo[]>;
1945
+ /**
1946
+ * Calculate the retention boundary index.
1947
+ * Returns the index of the oldest commit to KEEP.
1948
+ * All commits before this index will be squashed into a baseline.
1949
+ *
1950
+ * Strategy: find the tighter constraint between age and count.
1951
+ * - Age: keep commits newer than maxAgeDays
1952
+ * - Count: keep the last maxVersions commits
1953
+ * The boundary is the one that retains FEWER old commits (tighter).
1954
+ */
1955
+ calculateRetentionBoundary(commits: CommitInfo[]): number;
1956
+ /**
1957
+ * Perform the squash: create orphan with baseline + cherry-pick retained commits.
1958
+ */
1959
+ private performSquash;
1960
+ /**
1961
+ * Force push to remote after squash (history rewrite requires force).
1962
+ */
1963
+ private forcePushIfConfigured;
1964
+ }
1965
+
1966
+ export { CommitMessageGenerator, ContentHashCache, DocumentProcessor, EnrichmentStore, EventQueue, FileSystemWatcher, GitignoreFilter, InitialScanTracker, IssuesManager, JeevesWatcher, ReindexTracker, SquashManager, SystemHealth, TemplateEngine, ValuesManager, VcsCoordinator, VcsManager, VectorStoreClient, VirtualRuleStore, applyRules, buildAttributes, buildTemplateEngine, compileRules, contentHash, createApiServer, createEmbeddingProvider, createHandlebarsInstance, createLogger, extractText, issueRecordSchema, loadConfig, loadCustomHelpers, mergeEnrichment, pointId, registerBuiltinHelpers, resolveTemplateSource, startFromConfig, watcherDescriptor };
1967
+ export type { AllHelpersIntrospection, ApiServerOptions, ApplyRulesOptions, ApplyRulesResult, CollectionInfo, CommitInfo, CompiledRule, CompiledTemplate, DocumentProcessorDeps, DocumentProcessorInterface, EmbeddingProvider, EnrichmentStoreInterface, EventQueueOptions, ExtractedText, Extractor, FileAttributes, FileSystemWatcherOptions, HelperModuleIntrospection, InitialScanStatus, IssueRecord, IssuesFile, JeevesWatcherFactories, JeevesWatcherRuntimeOptions, PayloadFieldSchema, PendingReversion, ProcessFn, ProcessorConfig, ProviderFactory, PushError, ReindexStatus, RenderResult, ResolvedWatchRoot, RuleLogger, ScrollPageResult, ScrolledPoint, SearchResult, SquashResult, SystemHealthOptions, ValuesIndex, VectorPoint, VectorStore, WatchEvent };