@karmaniverous/jeeves-watcher 0.20.0 → 0.21.0-0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +16 -12
- package/config.schema.json +412 -210
- package/dist/cli/jeeves-watcher/{index-C9-xTM7k.js → index-CGVLEt3K.js} +18638 -11198
- package/dist/cli/jeeves-watcher/index.js +583 -185
- package/dist/index.d.ts +918 -407
- package/dist/index.js +19482 -11667
- package/package.json +32 -22
package/dist/index.d.ts
CHANGED
|
@@ -1,13 +1,14 @@
|
|
|
1
1
|
import { FastifyInstance } from 'fastify';
|
|
2
2
|
import { JeevesComponentDescriptor } from '@karmaniverous/jeeves';
|
|
3
|
+
import { EmbeddingConfig, IssueRecord, InferenceRule, SchemaEntry, SourcesConfig, VectorStoreConfig, DocumentResult, DocumentRejectionError, DocumentFailure, VcsRetentionConfig, VcsConfig, JeevesWatcherConfig, VcsHealth, InitialScanStatus, RestartCause, ConfigWatchReindexScope, ChangeSourceHealth, WatchConfig, ReindexStatus, IndexCheckHealth, LoggingConfig } from '@karmaniverous/jeeves-watcher-core';
|
|
4
|
+
export { ApiConfig, ConfigWatchConfig, EmbeddingConfig, InferenceRule, InitialScanStatus, IssueRecord, JeevesWatcherConfig, JeevesWatcherConfigInput, LoggingConfig, ReindexStatus, VectorStoreConfig, WatchConfig, apiConfigSchema, configWatchConfigSchema, embeddingConfigSchema, inferenceRuleSchema, issueRecordSchema, jeevesWatcherConfigSchema, loggingConfigSchema, vectorStoreConfigSchema, watchConfigSchema } from '@karmaniverous/jeeves-watcher-core';
|
|
3
5
|
import pino from 'pino';
|
|
4
|
-
import { EmbeddingConfig, IssueRecord, InferenceRule, SchemaEntry, SourcesConfig, VectorStoreConfig, DocumentResult, DocumentRejectionError, DocumentFailure, VcsConfig, JeevesWatcherConfig, WatchConfig, LoggingConfig, VcsRetentionConfig } from '@karmaniverous/jeeves-watcher-core';
|
|
5
|
-
export { ApiConfig, ConfigWatchConfig, EmbeddingConfig, InferenceRule, IssueRecord, JeevesWatcherConfig, JeevesWatcherConfigInput, LoggingConfig, VectorStoreConfig, WatchConfig, apiConfigSchema, configWatchConfigSchema, embeddingConfigSchema, inferenceRuleSchema, issueRecordSchema, jeevesWatcherConfigSchema, loggingConfigSchema, vectorStoreConfigSchema, watchConfigSchema } from '@karmaniverous/jeeves-watcher-core';
|
|
6
6
|
import { ErrorObject } from 'ajv';
|
|
7
7
|
import Handlebars from 'handlebars';
|
|
8
8
|
import { z } from 'zod';
|
|
9
|
-
import { JsonMapMap } from '@karmaniverous/jsonmap';
|
|
10
9
|
import { Stats } from 'node:fs';
|
|
10
|
+
import ParcelWatcher from '@parcel/watcher';
|
|
11
|
+
import { JsonMapMap } from '@karmaniverous/jsonmap';
|
|
11
12
|
|
|
12
13
|
/**
|
|
13
14
|
* @module embedding/types
|
|
@@ -80,6 +81,38 @@ type ProviderFactory = (config: EmbeddingConfig, logger?: pino.Logger) => Embedd
|
|
|
80
81
|
*/
|
|
81
82
|
declare function createEmbeddingProvider(config: EmbeddingConfig, logger?: pino.Logger, additionalProviders?: Map<string, ProviderFactory>): EmbeddingProvider;
|
|
82
83
|
|
|
84
|
+
/**
|
|
85
|
+
* @module embedding/EmbeddingHealth
|
|
86
|
+
* Embedding health (D86, D88, D89): wraps the shared rate-limited provider and tracks ok/failing (3+ failures since the last success and 60 s without one), with transition logs and alerts. Health shows codes, never provider text.
|
|
87
|
+
*
|
|
88
|
+
* A rate-limit wait that later succeeds is not a failure; any error a call
|
|
89
|
+
* throws (including a fail-fast `EmbeddingUnavailableError`) is. The first
|
|
90
|
+
* success returns the state to `ok`.
|
|
91
|
+
*/
|
|
92
|
+
|
|
93
|
+
/** Embedding health state. */
|
|
94
|
+
type EmbeddingHealthState = 'ok' | 'failing';
|
|
95
|
+
/** The most recent embedding error: when, and a machine-readable code. */
|
|
96
|
+
interface EmbeddingErrorSummary {
|
|
97
|
+
/** ISO timestamp. */
|
|
98
|
+
at: string;
|
|
99
|
+
/** `rate_limited`, `timeout`, `http_<status>`, `network` or `error`. */
|
|
100
|
+
code: string;
|
|
101
|
+
}
|
|
102
|
+
/** `GET /status` `health.embedding`. */
|
|
103
|
+
interface EmbeddingHealthSnapshot {
|
|
104
|
+
/** `ok` or `failing`. */
|
|
105
|
+
state: EmbeddingHealthState;
|
|
106
|
+
/** Last successful call (ISO), `null` before the first. */
|
|
107
|
+
lastSuccessAt: string | null;
|
|
108
|
+
/** Most recent error, `null` if none yet. */
|
|
109
|
+
lastError: EmbeddingErrorSummary | null;
|
|
110
|
+
/** When the state turned `failing` (ISO), `null` while `ok`. */
|
|
111
|
+
failingSince: string | null;
|
|
112
|
+
/** End of the stored provider back-off (ISO), `null` if none. */
|
|
113
|
+
backoffUntil: string | null;
|
|
114
|
+
}
|
|
115
|
+
|
|
83
116
|
/**
|
|
84
117
|
* @module enrichment/EnrichmentStore
|
|
85
118
|
* SQLite-backed enrichment metadata store. Persists path- or source-reference-keyed metadata (references verbatim) at stateDir/enrichments.sqlite. Atomic writes, supports move.
|
|
@@ -602,6 +635,60 @@ declare class VirtualRuleStore {
|
|
|
602
635
|
get size(): number;
|
|
603
636
|
}
|
|
604
637
|
|
|
638
|
+
/**
|
|
639
|
+
* @module processor/DocumentLocks
|
|
640
|
+
* One in-process FIFO lock per document key (D98): every process, delete, move, too_large and metadata change of a document runs under it. API routes wait at most 10 s, then 503 (D118). Idle locks are dropped.
|
|
641
|
+
*
|
|
642
|
+
* Keys: the normalised file path (the same normalisation as point IDs) or
|
|
643
|
+
* the source reference. A move takes both keys in sorted order, so two moves
|
|
644
|
+
* cannot deadlock.
|
|
645
|
+
*/
|
|
646
|
+
|
|
647
|
+
/** Options of one locked operation. */
|
|
648
|
+
interface DocumentLockOptions {
|
|
649
|
+
/** Longest wait for the lock (omit: unbounded, as for background work). */
|
|
650
|
+
lockWaitMs?: number;
|
|
651
|
+
}
|
|
652
|
+
/**
|
|
653
|
+
* The lock key of a file.
|
|
654
|
+
*
|
|
655
|
+
* @param filePath - The file path, as given.
|
|
656
|
+
* @returns The normalised path (lower-case, forward slashes).
|
|
657
|
+
*/
|
|
658
|
+
declare function fileLockKey(filePath: string): string;
|
|
659
|
+
/** The per-document locks of one processor. */
|
|
660
|
+
declare class DocumentLocks {
|
|
661
|
+
private readonly logger;
|
|
662
|
+
private readonly locks;
|
|
663
|
+
/** @param logger - Logger for long-hold warnings. */
|
|
664
|
+
constructor(logger: pino.Logger);
|
|
665
|
+
/** Number of keys currently locked or waited for. */
|
|
666
|
+
get size(): number;
|
|
667
|
+
/**
|
|
668
|
+
* Run `work` under the lock of `key`.
|
|
669
|
+
*
|
|
670
|
+
* @param key - Document key ({@link fileLockKey} or a source reference).
|
|
671
|
+
* @param operation - Operation name (warnings, timeout error).
|
|
672
|
+
* @param work - The work (must not take the same key again).
|
|
673
|
+
* @param options - Bounded wait.
|
|
674
|
+
* @returns What `work` returns.
|
|
675
|
+
* @throws DocumentLockTimeoutError when a bounded wait runs out.
|
|
676
|
+
*/
|
|
677
|
+
run<T>(key: string, operation: string, work: () => Promise<T>, options?: DocumentLockOptions): Promise<T>;
|
|
678
|
+
/**
|
|
679
|
+
* Run `work` holding the locks of every key, taken one at a time in sorted
|
|
680
|
+
* order (duplicates once).
|
|
681
|
+
*
|
|
682
|
+
* @param keys - Document keys.
|
|
683
|
+
* @param operation - Operation name.
|
|
684
|
+
* @param work - The work.
|
|
685
|
+
* @param options - Bounded wait (per lock).
|
|
686
|
+
* @returns What `work` returns.
|
|
687
|
+
*/
|
|
688
|
+
runAll<T>(keys: string[], operation: string, work: () => Promise<T>, options?: DocumentLockOptions): Promise<T>;
|
|
689
|
+
private lockFor;
|
|
690
|
+
}
|
|
691
|
+
|
|
605
692
|
/**
|
|
606
693
|
* @module cache/ContentHashCache
|
|
607
694
|
* In-memory cache mapping normalized file paths to content hashes.
|
|
@@ -860,6 +947,74 @@ declare class ValuesManager extends BinaryFileStore<ValuesIndex> {
|
|
|
860
947
|
getForRule(ruleName: string): Record<string, unknown[]>;
|
|
861
948
|
}
|
|
862
949
|
|
|
950
|
+
/**
|
|
951
|
+
* @module vectorStore/systemIndexes
|
|
952
|
+
* System payload indexes (D74, D154, D155): created at startup by background wait=true calls (startup never waits), reported as building, ready, conflict or failed; plus keyword-index readiness for by-filter writes. Qdrant I/O.
|
|
953
|
+
*
|
|
954
|
+
* `chunk_index` (integer) lets `countFacets` count documents, not chunks;
|
|
955
|
+
* `file_path` (keyword) serves metadata writes by filter (D139);
|
|
956
|
+
* `matched_rules` (keyword) serves rule-scoped counts (D155). A field
|
|
957
|
+
* already indexed with another type is left alone (`conflict`): writes keep
|
|
958
|
+
* using ID addressing, and `countFacets` answers 503 naming the index.
|
|
959
|
+
*/
|
|
960
|
+
|
|
961
|
+
/** State of one system index (`GET /status` `health.collection.systemIndexes`). */
|
|
962
|
+
type SystemIndexState = 'building' | 'ready' | 'conflict' | 'failed';
|
|
963
|
+
|
|
964
|
+
/**
|
|
965
|
+
* @module vectorStore/facets
|
|
966
|
+
* Qdrant reads behind `countFacets` (spec Design 12): approximate facet counts (D194), one-point ordered scrolls for a field's range, and the collection's payload index types. Every count and scroll passes Qdrant's `timeout` (whole seconds) so an abandoned call also stops in Qdrant. Qdrant I/O.
|
|
967
|
+
*/
|
|
968
|
+
|
|
969
|
+
/** A facet value as Qdrant reports it. */
|
|
970
|
+
type FacetValue = string | number | boolean;
|
|
971
|
+
/** One counted value. */
|
|
972
|
+
interface FacetHit {
|
|
973
|
+
/** The payload value. */
|
|
974
|
+
value: FacetValue;
|
|
975
|
+
/** Points holding it. */
|
|
976
|
+
count: number;
|
|
977
|
+
}
|
|
978
|
+
/** Which end of a range an ordered scroll reads. */
|
|
979
|
+
type RangeEnd = 'min' | 'max';
|
|
980
|
+
/** A range bound: a number, a stored date string, or null when nothing matched. */
|
|
981
|
+
type RangeBound = number | string | null;
|
|
982
|
+
/** One facet count or range read: field, filter and Qdrant timeout. */
|
|
983
|
+
interface FacetRead {
|
|
984
|
+
/** Payload field. */
|
|
985
|
+
field: string;
|
|
986
|
+
/** Qdrant filter (already scoped by the caller). */
|
|
987
|
+
filter: Record<string, unknown>;
|
|
988
|
+
/** Qdrant `timeout` query parameter, whole seconds. */
|
|
989
|
+
timeoutS: number;
|
|
990
|
+
}
|
|
991
|
+
/** Facet reads used by `countFacets` (`VectorStoreClient.facets`). */
|
|
992
|
+
interface FacetStore {
|
|
993
|
+
/**
|
|
994
|
+
* Approximate value counts of a field, highest first (D194).
|
|
995
|
+
*
|
|
996
|
+
* @param read - Field, filter and timeout.
|
|
997
|
+
* @param limit - Most values returned.
|
|
998
|
+
* @returns The counted values.
|
|
999
|
+
*/
|
|
1000
|
+
facetCounts(read: FacetRead, limit: number): Promise<FacetHit[]>;
|
|
1001
|
+
/**
|
|
1002
|
+
* One end of a field's range over the filter.
|
|
1003
|
+
*
|
|
1004
|
+
* @param read - Field, filter and timeout.
|
|
1005
|
+
* @param end - `min` or `max`.
|
|
1006
|
+
* @returns The bound, or null when no point holds the field.
|
|
1007
|
+
*/
|
|
1008
|
+
rangeBound(read: FacetRead, end: RangeEnd): Promise<RangeBound>;
|
|
1009
|
+
/** @returns Payload index type by field (`keyword`, `integer`, ...). */
|
|
1010
|
+
payloadIndexTypes(): Promise<Record<string, string>>;
|
|
1011
|
+
/**
|
|
1012
|
+
* @param field - A system index field (`chunk_index`, `matched_rules`).
|
|
1013
|
+
* @returns Its state, or undefined before startup.
|
|
1014
|
+
*/
|
|
1015
|
+
systemIndexState(field: string): SystemIndexState | undefined;
|
|
1016
|
+
}
|
|
1017
|
+
|
|
863
1018
|
/**
|
|
864
1019
|
* @module vectorStore/types
|
|
865
1020
|
* Vector store interface and type definitions.
|
|
@@ -961,6 +1116,37 @@ interface VectorStore {
|
|
|
961
1116
|
* @param keys - Payload keys to remove.
|
|
962
1117
|
*/
|
|
963
1118
|
deletePayload(ids: string[], keys: string[]): Promise<void>;
|
|
1119
|
+
/**
|
|
1120
|
+
* Whether `field` has a ready `keyword` payload index, so a by-filter
|
|
1121
|
+
* write on it is cheap (D154). A system index counts once its background
|
|
1122
|
+
* build returned; any other field when it was keyword-indexed at startup.
|
|
1123
|
+
*
|
|
1124
|
+
* @param field - Payload field.
|
|
1125
|
+
* @returns True when by-filter writes on `field` may be used.
|
|
1126
|
+
*/
|
|
1127
|
+
keywordIndexReady(field: string): boolean;
|
|
1128
|
+
/**
|
|
1129
|
+
* Set payload fields on every point matching a filter (D139).
|
|
1130
|
+
*
|
|
1131
|
+
* @param filter - Qdrant filter selecting one document's points.
|
|
1132
|
+
* @param payload - Payload fields to set.
|
|
1133
|
+
*/
|
|
1134
|
+
setPayloadWhere(filter: Record<string, unknown>, payload: Record<string, unknown>): Promise<void>;
|
|
1135
|
+
/**
|
|
1136
|
+
* Remove payload keys from every point matching a filter (D139).
|
|
1137
|
+
*
|
|
1138
|
+
* @param filter - Qdrant filter selecting one document's points.
|
|
1139
|
+
* @param keys - Payload keys to remove.
|
|
1140
|
+
*/
|
|
1141
|
+
deletePayloadWhere(filter: Record<string, unknown>, keys: string[]): Promise<void>;
|
|
1142
|
+
/**
|
|
1143
|
+
* The IDs among `ids` that exist, in the given order (no payload, no
|
|
1144
|
+
* vectors; needs no index, D154).
|
|
1145
|
+
*
|
|
1146
|
+
* @param ids - Candidate point IDs.
|
|
1147
|
+
* @returns The existing IDs.
|
|
1148
|
+
*/
|
|
1149
|
+
existingIds(ids: string[]): Promise<string[]>;
|
|
964
1150
|
/**
|
|
965
1151
|
* Get the payload of a point by ID.
|
|
966
1152
|
*
|
|
@@ -1041,6 +1227,8 @@ interface VectorStore {
|
|
|
1041
1227
|
* fresh client (see QdrantWriter).
|
|
1042
1228
|
*/
|
|
1043
1229
|
declare class VectorStoreClient implements VectorStore {
|
|
1230
|
+
/** Facet reads behind `countFacets` (spec Design 12). */
|
|
1231
|
+
readonly facets: FacetStore;
|
|
1044
1232
|
private readonly client;
|
|
1045
1233
|
private readonly writer;
|
|
1046
1234
|
private readonly clientConfig;
|
|
@@ -1048,6 +1236,7 @@ declare class VectorStoreClient implements VectorStore {
|
|
|
1048
1236
|
private readonly dims;
|
|
1049
1237
|
private readonly pinoLogger?;
|
|
1050
1238
|
private readonly payloadIndexes;
|
|
1239
|
+
private readonly systemIndexes;
|
|
1051
1240
|
/**
|
|
1052
1241
|
* Create a new VectorStoreClient.
|
|
1053
1242
|
*
|
|
@@ -1066,18 +1255,26 @@ declare class VectorStoreClient implements VectorStore {
|
|
|
1066
1255
|
* (see QdrantWriter).
|
|
1067
1256
|
*/
|
|
1068
1257
|
private createClient;
|
|
1069
|
-
/**
|
|
1070
|
-
* Count points matching a filter.
|
|
1071
|
-
*
|
|
1072
|
-
* @param filter - Optional Qdrant filter.
|
|
1073
|
-
* @returns The number of matching points.
|
|
1074
|
-
*/
|
|
1258
|
+
/** {@inheritDoc VectorStore.count} */
|
|
1075
1259
|
count(filter?: Record<string, unknown>): Promise<number>;
|
|
1076
1260
|
/**
|
|
1077
1261
|
* Ensure the collection exists (Cosine, configured dimensions) and create
|
|
1078
|
-
* any missing payload indexes (configured plus `source`/`source_rule`)
|
|
1262
|
+
* any missing payload indexes (configured plus `source`/`source_rule`),
|
|
1263
|
+
* then start the background system-index builds (D74, D154; not awaited).
|
|
1079
1264
|
*/
|
|
1080
1265
|
ensureCollection(): Promise<void>;
|
|
1266
|
+
/** @returns Each system index's state (`health.collection.systemIndexes`). */
|
|
1267
|
+
systemIndexStates(): Record<string, SystemIndexState>;
|
|
1268
|
+
/** @returns A promise settling once the background index builds end. */
|
|
1269
|
+
whenSystemIndexesSettled(): Promise<void>;
|
|
1270
|
+
/** {@inheritDoc VectorStore.keywordIndexReady} */
|
|
1271
|
+
keywordIndexReady(field: string): boolean;
|
|
1272
|
+
/** {@inheritDoc VectorStore.setPayloadWhere} */
|
|
1273
|
+
setPayloadWhere(filter: Record<string, unknown>, payload: Record<string, unknown>): Promise<void>;
|
|
1274
|
+
/** {@inheritDoc VectorStore.deletePayloadWhere} */
|
|
1275
|
+
deletePayloadWhere(filter: Record<string, unknown>, keys: string[]): Promise<void>;
|
|
1276
|
+
/** {@inheritDoc VectorStore.existingIds} */
|
|
1277
|
+
existingIds(ids: string[]): Promise<string[]>;
|
|
1081
1278
|
/** {@inheritDoc VectorStore.upsert} */
|
|
1082
1279
|
upsert(points: VectorPoint[]): Promise<void>;
|
|
1083
1280
|
/** {@inheritDoc VectorStore.delete} */
|
|
@@ -1086,77 +1283,39 @@ declare class VectorStoreClient implements VectorStore {
|
|
|
1086
1283
|
setPayload(ids: string[], payload: Record<string, unknown>): Promise<void>;
|
|
1087
1284
|
/** {@inheritDoc VectorStore.deletePayload} */
|
|
1088
1285
|
deletePayload(ids: string[], keys: string[]): Promise<void>;
|
|
1089
|
-
/**
|
|
1090
|
-
* Get the payload of a point by ID.
|
|
1091
|
-
*
|
|
1092
|
-
* @param id - The point ID.
|
|
1093
|
-
* @returns The payload, or `null` if the point doesn't exist.
|
|
1094
|
-
* @throws When the read fails (never reported as a missing point).
|
|
1095
|
-
*/
|
|
1286
|
+
/** {@inheritDoc VectorStore.getPayload} */
|
|
1096
1287
|
getPayload(id: string): Promise<Record<string, unknown> | null>;
|
|
1097
|
-
/**
|
|
1098
|
-
* Get collection info including point count, dimensions, and payload field schema.
|
|
1099
|
-
*
|
|
1100
|
-
* When Qdrant has payload indexes, uses `payload_schema` directly. Otherwise
|
|
1101
|
-
* samples points to discover fields and infer types.
|
|
1102
|
-
*/
|
|
1288
|
+
/** {@inheritDoc VectorStore.getCollectionInfo} */
|
|
1103
1289
|
getCollectionInfo(): Promise<CollectionInfo>;
|
|
1104
|
-
/**
|
|
1105
|
-
* Search for similar vectors.
|
|
1106
|
-
*
|
|
1107
|
-
* @param vector - The query vector.
|
|
1108
|
-
* @param limit - Maximum results to return.
|
|
1109
|
-
* @param filter - Optional Qdrant filter.
|
|
1110
|
-
* @returns An array of search results.
|
|
1111
|
-
*/
|
|
1290
|
+
/** {@inheritDoc VectorStore.search} */
|
|
1112
1291
|
search(vector: number[], limit: number, filter?: Record<string, unknown>, offset?: number): Promise<SearchResult[]>;
|
|
1113
|
-
/**
|
|
1114
|
-
* Create a full-text payload index on the specified field.
|
|
1115
|
-
* Idempotent — skips if the field already has a text index.
|
|
1116
|
-
*
|
|
1117
|
-
* @param fieldName - The payload field to index.
|
|
1118
|
-
*/
|
|
1292
|
+
/** {@inheritDoc VectorStore.ensureTextIndex} */
|
|
1119
1293
|
ensureTextIndex(fieldName: string): Promise<void>;
|
|
1120
|
-
/**
|
|
1121
|
-
* Hybrid search combining dense vector and full-text match with RRF fusion.
|
|
1122
|
-
*
|
|
1123
|
-
* @param vector - The query vector.
|
|
1124
|
-
* @param queryText - The raw query text for full-text matching.
|
|
1125
|
-
* @param limit - Maximum results to return.
|
|
1126
|
-
* @param textWeight - Weight for text results in RRF (0–1).
|
|
1127
|
-
* @param filter - Optional Qdrant filter.
|
|
1128
|
-
* @param offset - Optional result offset for pagination.
|
|
1129
|
-
* @returns An array of search results.
|
|
1130
|
-
*/
|
|
1294
|
+
/** {@inheritDoc VectorStore.hybridSearch} */
|
|
1131
1295
|
hybridSearch(vector: number[], queryText: string, limit: number, textWeight: number, filter?: Record<string, unknown>, offset?: number): Promise<SearchResult[]>;
|
|
1132
|
-
/**
|
|
1133
|
-
* Retrieve points with their vectors by ID.
|
|
1134
|
-
*
|
|
1135
|
-
* @param ids - The point IDs to retrieve.
|
|
1136
|
-
* @returns Points with vectors and payloads; missing IDs are omitted.
|
|
1137
|
-
* @throws When the read fails (never reported as missing points).
|
|
1138
|
-
*/
|
|
1296
|
+
/** {@inheritDoc VectorStore.getPointsWithVectors} */
|
|
1139
1297
|
getPointsWithVectors(ids: string[]): Promise<VectorPoint[]>;
|
|
1140
|
-
/**
|
|
1141
|
-
* Scroll one page of points matching a filter.
|
|
1142
|
-
*
|
|
1143
|
-
* @param filter - Optional Qdrant filter.
|
|
1144
|
-
* @param limit - Page size.
|
|
1145
|
-
* @param offset - Cursor offset from previous page.
|
|
1146
|
-
* @param fields - Optional field projection.
|
|
1147
|
-
* @returns Page of points and next cursor.
|
|
1148
|
-
*/
|
|
1298
|
+
/** {@inheritDoc VectorStore.scrollPage} */
|
|
1149
1299
|
scrollPage(filter?: Record<string, unknown>, limit?: number, offset?: string | number, fields?: string[]): Promise<ScrollPageResult>;
|
|
1150
|
-
/**
|
|
1151
|
-
* Scroll through all points matching a filter.
|
|
1152
|
-
*
|
|
1153
|
-
* @param filter - Optional Qdrant filter.
|
|
1154
|
-
* @param limit - Page size for scrolling.
|
|
1155
|
-
* @yields Scrolled points.
|
|
1156
|
-
*/
|
|
1300
|
+
/** {@inheritDoc VectorStore.scroll} */
|
|
1157
1301
|
scroll(filter?: Record<string, unknown>, limit?: number): AsyncGenerator<ScrolledPoint>;
|
|
1158
1302
|
}
|
|
1159
1303
|
|
|
1304
|
+
/**
|
|
1305
|
+
* @module processor/processingLimits
|
|
1306
|
+
* Resolve the `processing` ceilings (D44, D64) from the live config to bytes and a chunk count; read per document, so a reload applies to the next one. Pure.
|
|
1307
|
+
*/
|
|
1308
|
+
|
|
1309
|
+
/** The resolved ceilings. */
|
|
1310
|
+
interface ProcessingLimits {
|
|
1311
|
+
/** Largest file processed (bytes, checked with `stat` before extraction). */
|
|
1312
|
+
maxFileBytes: number;
|
|
1313
|
+
/** Most chunks one document may split into. */
|
|
1314
|
+
maxChunksPerFile: number;
|
|
1315
|
+
/** Largest extracted text (UTF-8 bytes). */
|
|
1316
|
+
maxTextBytes: number;
|
|
1317
|
+
}
|
|
1318
|
+
|
|
1160
1319
|
/**
|
|
1161
1320
|
* @module processor/ProcessorConfig
|
|
1162
1321
|
* Configuration interface for DocumentProcessor, extracted for single-responsibility.
|
|
@@ -1211,6 +1370,10 @@ interface DocumentProcessorDeps {
|
|
|
1211
1370
|
contentHashCache?: ContentHashCache;
|
|
1212
1371
|
/** Optional source callback client; without it, source documents fail `source_unavailable`. */
|
|
1213
1372
|
sourceRetriever?: SourceRetriever;
|
|
1373
|
+
/** Per-document locks (D98); default: the processor's own. */
|
|
1374
|
+
documentLocks?: DocumentLocks;
|
|
1375
|
+
/** The processing ceilings, read per document (D44); default: every default. */
|
|
1376
|
+
getProcessingLimits?: () => ProcessingLimits;
|
|
1214
1377
|
}
|
|
1215
1378
|
|
|
1216
1379
|
/**
|
|
@@ -1236,7 +1399,7 @@ interface RenderResult {
|
|
|
1236
1399
|
|
|
1237
1400
|
/**
|
|
1238
1401
|
* @module processor/documentPipeline
|
|
1239
|
-
* The shared indexing pipeline for resolved documents (file or source): onResolved hook, empty check, hash compare,
|
|
1402
|
+
* The shared indexing pipeline for resolved documents (file or source): onResolved hook, empty check, text and chunk ceilings (too_large), hash compare, streamed embed and upsert; plus point deletion.
|
|
1240
1403
|
*/
|
|
1241
1404
|
|
|
1242
1405
|
/**
|
|
@@ -1282,8 +1445,18 @@ interface SourceOperationsInterface {
|
|
|
1282
1445
|
compiledRule(name: string): CompiledRule | undefined;
|
|
1283
1446
|
/** Retrieve and render a document without embedding or writing anything. */
|
|
1284
1447
|
render(ref: string, rule: string): Promise<SourceRenderOutcome>;
|
|
1285
|
-
/**
|
|
1286
|
-
|
|
1448
|
+
/**
|
|
1449
|
+
* Merge enrichment metadata into an indexed document's points; `null` if
|
|
1450
|
+
* not indexed. `options.lockWaitMs` bounds the document-lock wait (D118).
|
|
1451
|
+
*/
|
|
1452
|
+
updateMetadata(ref: string, metadata: Record<string, unknown>, options?: DocumentLockOptions): Promise<Record<string, unknown> | null>;
|
|
1453
|
+
/**
|
|
1454
|
+
* Run `work` under the processor's document lock of `ref` (D98), e.g. a
|
|
1455
|
+
* whole-document delete. `ref` is any document key: a source reference,
|
|
1456
|
+
* or `fileLockKey(path)` for a file (`POST /rebuild-metadata`).
|
|
1457
|
+
* `options.lockWaitMs` bounds the wait (D118).
|
|
1458
|
+
*/
|
|
1459
|
+
withLock<T>(ref: string, operation: string, work: () => Promise<T>, options?: DocumentLockOptions): Promise<T>;
|
|
1287
1460
|
}
|
|
1288
1461
|
/** A processor exposing source operations (`DocumentProcessor` implements it). */
|
|
1289
1462
|
interface SourceOperationsProvider {
|
|
@@ -1306,10 +1479,16 @@ interface DocumentProcessorInterface {
|
|
|
1306
1479
|
processFile(filePath: string): Promise<void>;
|
|
1307
1480
|
/** Delete a file's points/metadata from the system. */
|
|
1308
1481
|
deleteFile(filePath: string): Promise<void>;
|
|
1309
|
-
/**
|
|
1310
|
-
|
|
1311
|
-
|
|
1312
|
-
|
|
1482
|
+
/**
|
|
1483
|
+
* Process a metadata sidecar update for a file (payload update only).
|
|
1484
|
+
* `options.lockWaitMs` bounds the document-lock wait (API routes, D118).
|
|
1485
|
+
*/
|
|
1486
|
+
processMetadataUpdate(filePath: string, metadata: Record<string, unknown>, options?: DocumentLockOptions): Promise<Record<string, unknown> | null>;
|
|
1487
|
+
/**
|
|
1488
|
+
* Process a rules update for a file (rebuild merged metadata, payload
|
|
1489
|
+
* update only). `options.lockWaitMs` bounds the document-lock wait.
|
|
1490
|
+
*/
|
|
1491
|
+
processRulesUpdate(filePath: string, options?: DocumentLockOptions): Promise<Record<string, unknown> | null>;
|
|
1313
1492
|
/** Render a file through the rule engine without embedding. */
|
|
1314
1493
|
renderFile(filePath: string): Promise<RenderResult>;
|
|
1315
1494
|
/** Move a file's vector points and metadata from old path to new path (no re-embed). */
|
|
@@ -1337,23 +1516,19 @@ type WatcherProcessor = DocumentProcessorInterface & SourceOperationsProvider;
|
|
|
1337
1516
|
* Handles extracting text, computing embeddings, and syncing with the vector store.
|
|
1338
1517
|
*/
|
|
1339
1518
|
declare class DocumentProcessor implements WatcherProcessor {
|
|
1519
|
+
private readonly deps;
|
|
1340
1520
|
private config;
|
|
1341
|
-
private readonly embeddingProvider;
|
|
1342
|
-
private readonly vectorStore;
|
|
1343
1521
|
private compiledRules;
|
|
1344
|
-
private readonly logger;
|
|
1345
1522
|
private templateEngine?;
|
|
1346
|
-
private readonly
|
|
1347
|
-
private readonly issuesManager?;
|
|
1348
|
-
private readonly valuesManager?;
|
|
1349
|
-
private readonly contentHashCache?;
|
|
1350
|
-
private readonly sourceRetriever?;
|
|
1523
|
+
private readonly locks;
|
|
1351
1524
|
/**
|
|
1352
1525
|
* Create a new DocumentProcessor.
|
|
1353
1526
|
*
|
|
1354
1527
|
* @param deps - The processor dependencies.
|
|
1355
1528
|
*/
|
|
1356
1529
|
constructor(deps: DocumentProcessorDeps);
|
|
1530
|
+
/** The processing ceilings now (read per document, D44). */
|
|
1531
|
+
private limits;
|
|
1357
1532
|
/** Rule context reflecting the current rules, templates and config. */
|
|
1358
1533
|
private ruleContext;
|
|
1359
1534
|
/** Shared pipeline dependencies. */
|
|
@@ -1389,18 +1564,22 @@ declare class DocumentProcessor implements WatcherProcessor {
|
|
|
1389
1564
|
*
|
|
1390
1565
|
* @param filePath - The file whose metadata to update.
|
|
1391
1566
|
* @param metadata - The new metadata to merge.
|
|
1567
|
+
* @param options - Bounded lock wait (API routes, D118).
|
|
1392
1568
|
* @returns The merged payload, or `null` if the file is not indexed.
|
|
1569
|
+
* @throws DocumentLockTimeoutError when a bounded lock wait runs out.
|
|
1393
1570
|
*/
|
|
1394
|
-
processMetadataUpdate(filePath: string, metadata: Record<string, unknown
|
|
1571
|
+
processMetadataUpdate(filePath: string, metadata: Record<string, unknown>, options?: DocumentLockOptions): Promise<Record<string, unknown> | null>;
|
|
1395
1572
|
/**
|
|
1396
1573
|
* Re-apply inference rules to a file without re-embedding (see
|
|
1397
1574
|
* `reapplyFileRules`: system fields and the stored `file_path` are
|
|
1398
1575
|
* re-asserted; interpolation failures are recorded as an issue).
|
|
1399
1576
|
*
|
|
1400
1577
|
* @param filePath - The file to update.
|
|
1578
|
+
* @param options - Bounded lock wait (API routes, D118).
|
|
1401
1579
|
* @returns The merged metadata, or `null` if the file is not indexed.
|
|
1580
|
+
* @throws DocumentLockTimeoutError when a bounded lock wait runs out.
|
|
1402
1581
|
*/
|
|
1403
|
-
processRulesUpdate(filePath: string): Promise<Record<string, unknown> | null>;
|
|
1582
|
+
processRulesUpdate(filePath: string, options?: DocumentLockOptions): Promise<Record<string, unknown> | null>;
|
|
1404
1583
|
/**
|
|
1405
1584
|
* Render a file through the rule engine without embedding.
|
|
1406
1585
|
* Returns rendered content, renderAs, matched rules, and metadata.
|
|
@@ -1715,6 +1894,166 @@ declare class CommitMessageGenerator {
|
|
|
1715
1894
|
generate(files: string[], diffSummary: string): Promise<string | null>;
|
|
1716
1895
|
}
|
|
1717
1896
|
|
|
1897
|
+
/**
|
|
1898
|
+
* @module vcs/RootGitLock
|
|
1899
|
+
* Per-root, in-process FIFO async mutex serialising the watcher's own git work on a root: batch commits (with push), squash, untracking and temp-file sweeps (D66, D81). Never re-entered. Logs long waits and holds; an API route's wait is bounded (D102).
|
|
1900
|
+
*
|
|
1901
|
+
* It cannot exclude other processes (people and agents run git in the same
|
|
1902
|
+
* repositories), so everything done under it must also be safe without it.
|
|
1903
|
+
*/
|
|
1904
|
+
|
|
1905
|
+
/** FIFO mutex for one VCS root. */
|
|
1906
|
+
declare class RootGitLock {
|
|
1907
|
+
private readonly lock;
|
|
1908
|
+
/**
|
|
1909
|
+
* @param root - Repository root (named in warnings).
|
|
1910
|
+
* @param logger - Logger for long-wait and long-hold warnings.
|
|
1911
|
+
*/
|
|
1912
|
+
constructor(root: string, logger: pino.Logger);
|
|
1913
|
+
/** The operation holding the lock, if any. */
|
|
1914
|
+
get heldBy(): string | undefined;
|
|
1915
|
+
/**
|
|
1916
|
+
* Run `work` while holding the lock. Callers queue in arrival order; the
|
|
1917
|
+
* lock is released when `work` settles, whatever its outcome.
|
|
1918
|
+
*
|
|
1919
|
+
* @param operation - Operation name, for warnings and {@link heldBy}.
|
|
1920
|
+
* @param work - The work to run under the lock (must not take it again).
|
|
1921
|
+
* @returns What `work` returns.
|
|
1922
|
+
*/
|
|
1923
|
+
run<T>(operation: string, work: () => Promise<T>): Promise<T>;
|
|
1924
|
+
/**
|
|
1925
|
+
* {@link run}, giving up when the lock is not acquired within `waitMs`
|
|
1926
|
+
* (D102). A caller that gives up never runs `work`; its place in the
|
|
1927
|
+
* queue passes straight on, so later callers keep their order.
|
|
1928
|
+
*
|
|
1929
|
+
* @param operation - Operation name, for warnings and {@link heldBy}.
|
|
1930
|
+
* @param waitMs - Longest wait for the lock.
|
|
1931
|
+
* @param work - The work to run under the lock (must not take it again).
|
|
1932
|
+
* @returns What `work` returns.
|
|
1933
|
+
* @throws LockWaitTimeoutError when the wait runs out.
|
|
1934
|
+
*/
|
|
1935
|
+
runWithin<T>(operation: string, waitMs: number, work: () => Promise<T>): Promise<T>;
|
|
1936
|
+
}
|
|
1937
|
+
|
|
1938
|
+
/**
|
|
1939
|
+
* @module vcs/squashPlumbing
|
|
1940
|
+
* Plumbing-only history rewrite for squash retention (D148, D166): list the first-parent history, rebuild it with `commit-tree` from a parentless baseline, keeping each retained commit's tree, raw message, identities and raw dates. Never touches the working tree or the index.
|
|
1941
|
+
*/
|
|
1942
|
+
/** Commit metadata for retention calculation. */
|
|
1943
|
+
interface CommitInfo {
|
|
1944
|
+
/** Full hash. */
|
|
1945
|
+
hash: string;
|
|
1946
|
+
/** Author date. */
|
|
1947
|
+
date: Date;
|
|
1948
|
+
}
|
|
1949
|
+
|
|
1950
|
+
/**
|
|
1951
|
+
* @module vcs/SquashManager
|
|
1952
|
+
* Scheduled squash retention for one VCS root: under RootGitLock, flush the pending batch, then rewrite the branch in plumbing and move it with a compare-and-swap `update-ref` (D101, D148, D166). Force-pushes when a remote is set.
|
|
1953
|
+
*
|
|
1954
|
+
* No checkout, reset or cherry-pick runs, so the working tree and the index
|
|
1955
|
+
* are never touched: a file untracked by `/vcs/exclude` or the size cap
|
|
1956
|
+
* keeps its newest content on disk, and no clean tree is needed. Squash
|
|
1957
|
+
* still refuses while a merge, rebase, cherry-pick or revert is in
|
|
1958
|
+
* progress, or when HEAD is not on the configured branch (D20).
|
|
1959
|
+
*/
|
|
1960
|
+
|
|
1961
|
+
/** Result of a squash operation. */
|
|
1962
|
+
interface SquashResult {
|
|
1963
|
+
squashed: boolean;
|
|
1964
|
+
commitsRemoved?: number;
|
|
1965
|
+
commitsRetained?: number;
|
|
1966
|
+
error?: string;
|
|
1967
|
+
}
|
|
1968
|
+
/** Test hooks around the reference update (not public API). @internal */
|
|
1969
|
+
interface SquashHooks {
|
|
1970
|
+
/** Receives the rebuilt tip; returns the tip to check and publish. */
|
|
1971
|
+
rebuiltTip?: (tip: string) => Promise<string>;
|
|
1972
|
+
/** Runs after the tree check, just before `update-ref`. */
|
|
1973
|
+
beforeUpdateRef?: () => Promise<void>;
|
|
1974
|
+
}
|
|
1975
|
+
/** Options for SquashManager construction beyond the required params. */
|
|
1976
|
+
interface SquashManagerOptions {
|
|
1977
|
+
/** Git branch name for squash operations. Default: "master". */
|
|
1978
|
+
branch?: string;
|
|
1979
|
+
/** The root's lock; squash holds it for its whole run (D81). */
|
|
1980
|
+
lock: RootGitLock;
|
|
1981
|
+
/**
|
|
1982
|
+
* Commit pending changes inside the hold through the non-locking commit
|
|
1983
|
+
* path (D101). Resolves false when that commit failed (squash refuses).
|
|
1984
|
+
*/
|
|
1985
|
+
flushInHold?: () => Promise<boolean>;
|
|
1986
|
+
/** Remote URL for force-push after squash. */
|
|
1987
|
+
remoteUrl?: string;
|
|
1988
|
+
/** Access token for HTTPS push authentication. */
|
|
1989
|
+
accessToken?: string;
|
|
1990
|
+
/** Test hooks (not public API). @internal */
|
|
1991
|
+
hooks?: SquashHooks;
|
|
1992
|
+
}
|
|
1993
|
+
/**
|
|
1994
|
+
* Manages scheduled squash retention for a single VCS root.
|
|
1995
|
+
*
|
|
1996
|
+
* Runs on a cron schedule (checked every 60s). When triggered, squashes
|
|
1997
|
+
* commits older than the retention boundary (the tighter of maxAgeDays
|
|
1998
|
+
* and maxVersions) into a single "historical baseline" commit and
|
|
1999
|
+
* recreates the retained commits on top of it.
|
|
2000
|
+
*/
|
|
2001
|
+
declare class SquashManager {
|
|
2002
|
+
private readonly rootPath;
|
|
2003
|
+
private readonly retention;
|
|
2004
|
+
private readonly logger;
|
|
2005
|
+
private readonly options;
|
|
2006
|
+
private readonly branch;
|
|
2007
|
+
private intervalTimer;
|
|
2008
|
+
private running;
|
|
2009
|
+
constructor(rootPath: string, retention: VcsRetentionConfig, logger: pino.Logger, options: SquashManagerOptions);
|
|
2010
|
+
/**
|
|
2011
|
+
* Start the cron-based squash scheduler.
|
|
2012
|
+
* Checks every 60 seconds if the cron expression matches.
|
|
2013
|
+
*/
|
|
2014
|
+
start(): void;
|
|
2015
|
+
/**
|
|
2016
|
+
* Stop the cron scheduler.
|
|
2017
|
+
*/
|
|
2018
|
+
stop(): void;
|
|
2019
|
+
/**
|
|
2020
|
+
* Run the squash under the root's lock: flush, guard, rewrite, publish,
|
|
2021
|
+
* force-push. Exposed publicly for testing.
|
|
2022
|
+
*/
|
|
2023
|
+
runSquash(): Promise<SquashResult>;
|
|
2024
|
+
/**
|
|
2025
|
+
* Refuse while an abandoned cherry-pick, rebase or merge is present, or
|
|
2026
|
+
* when HEAD is not on the configured branch (#249, D20: report only).
|
|
2027
|
+
*
|
|
2028
|
+
* @returns The refusal reason, or undefined if the squash may proceed.
|
|
2029
|
+
*/
|
|
2030
|
+
private checkRepoPreconditions;
|
|
2031
|
+
/** Rewrite and publish the branch (inside the hold). */
|
|
2032
|
+
private squashBranch;
|
|
2033
|
+
/** Log a finished squash, force push if configured, and report it. */
|
|
2034
|
+
private completed;
|
|
2035
|
+
/**
|
|
2036
|
+
* Get all first-parent commits of HEAD in chronological order (oldest
|
|
2037
|
+
* first), or none when HEAD is unborn.
|
|
2038
|
+
*/
|
|
2039
|
+
getCommitLog(): Promise<CommitInfo[]>;
|
|
2040
|
+
/**
|
|
2041
|
+
* Calculate the retention boundary index.
|
|
2042
|
+
* Returns the index of the oldest commit to KEEP.
|
|
2043
|
+
* All commits before this index will be squashed into a baseline.
|
|
2044
|
+
*
|
|
2045
|
+
* Strategy: find the tighter constraint between age and count.
|
|
2046
|
+
* - Age: keep commits newer than maxAgeDays
|
|
2047
|
+
* - Count: keep the last maxVersions commits
|
|
2048
|
+
* The boundary is the one that retains FEWER old commits (tighter).
|
|
2049
|
+
*/
|
|
2050
|
+
calculateRetentionBoundary(commits: CommitInfo[]): number;
|
|
2051
|
+
/**
|
|
2052
|
+
* Force push to remote after squash (history rewrite requires force).
|
|
2053
|
+
*/
|
|
2054
|
+
private forcePushIfConfigured;
|
|
2055
|
+
}
|
|
2056
|
+
|
|
1718
2057
|
/**
|
|
1719
2058
|
* @module vcs/types
|
|
1720
2059
|
* Shared types for the VCS subsystem.
|
|
@@ -1733,7 +2072,7 @@ interface PushError {
|
|
|
1733
2072
|
|
|
1734
2073
|
/**
|
|
1735
2074
|
* @module vcs/VcsManager
|
|
1736
|
-
* Per-root VCS manager for git-backed content versioning.
|
|
2075
|
+
* Per-root VCS manager for git-backed content versioning: a throttled batch queue, a circuit breaker, the root's RootGitLock, squash scheduling and startup maintenance. Commits run through {@link BatchCommitter} under the lock.
|
|
1737
2076
|
*/
|
|
1738
2077
|
|
|
1739
2078
|
/** Per-root circuit breaker state, exposed via /vcs/status. */
|
|
@@ -1741,75 +2080,56 @@ interface VcsBreakerState extends CircuitBreakerSnapshot {
|
|
|
1741
2080
|
/** Files queued or in flight, not yet committed. */
|
|
1742
2081
|
pendingCount: number;
|
|
1743
2082
|
}
|
|
2083
|
+
/** Optional VcsManager collaborators. */
|
|
2084
|
+
interface VcsManagerOptions {
|
|
2085
|
+
/** `vcs.maxFileBytes` in bytes, read at each staging (D67). */
|
|
2086
|
+
getMaxFileBytes?: () => number;
|
|
2087
|
+
/** Path-list timeout override (tests only). */
|
|
2088
|
+
timeoutFor?: (paths: number) => number;
|
|
2089
|
+
}
|
|
1744
2090
|
/**
|
|
1745
|
-
* Per-root VCS manager
|
|
1746
|
-
*
|
|
1747
|
-
* Each VCS-enabled watch root gets its own VcsManager instance, which owns
|
|
1748
|
-
* a throttled commit pipeline: file changes are batched, staged, committed
|
|
1749
|
-
* (with optional AI-generated messages), and optionally pushed to a remote.
|
|
1750
|
-
*
|
|
1751
|
-
* Concurrency: only one commit is in-flight at a time per root. Index.lock
|
|
1752
|
-
* contention is handled with exponential backoff retries (D10). Failed
|
|
1753
|
-
* batches are always retained; a circuit breaker spaces out retries of a
|
|
1754
|
-
* persistently failing root (#249).
|
|
2091
|
+
* Per-root VCS manager: batches file changes and commits them under the
|
|
2092
|
+
* root's {@link RootGitLock}; failed batches are always retained (#249).
|
|
1755
2093
|
*/
|
|
1756
2094
|
declare class VcsManager {
|
|
1757
2095
|
readonly config: VcsConfig;
|
|
1758
2096
|
readonly rootPath: string;
|
|
1759
2097
|
readonly remoteUrl: string | undefined;
|
|
1760
|
-
|
|
2098
|
+
/** Serialises this root's git work (D66, D81). */
|
|
2099
|
+
readonly lock: RootGitLock;
|
|
1761
2100
|
private readonly logger;
|
|
1762
|
-
private readonly
|
|
2101
|
+
private readonly committer;
|
|
1763
2102
|
private readonly breaker;
|
|
1764
|
-
private readonly
|
|
2103
|
+
private readonly queue;
|
|
1765
2104
|
private readonly pendingReversions;
|
|
1766
|
-
private readonly _pushErrors;
|
|
1767
2105
|
private readonly squashManager;
|
|
1768
|
-
private
|
|
1769
|
-
private breakerRetryTimer;
|
|
1770
|
-
private commitInFlight;
|
|
1771
|
-
private inFlightFileCount;
|
|
2106
|
+
private sweepTimer;
|
|
1772
2107
|
private started;
|
|
1773
|
-
private paused;
|
|
1774
2108
|
private isBaseline;
|
|
1775
|
-
|
|
1776
|
-
constructor(rootPath: string, config: VcsConfig, logger: pino.Logger, commitMessageGenerator?: CommitMessageGenerator, remoteUrl?: string, accessToken?: string);
|
|
2109
|
+
constructor(rootPath: string, config: VcsConfig, logger: pino.Logger, commitMessageGenerator?: CommitMessageGenerator, remoteUrl?: string, accessToken?: string, options?: VcsManagerOptions);
|
|
1777
2110
|
get lastPushTime(): string | null;
|
|
1778
2111
|
get pushErrors(): readonly PushError[];
|
|
1779
2112
|
/** Current circuit breaker state and backlog, for /vcs/status. */
|
|
1780
2113
|
get breakerState(): VcsBreakerState;
|
|
2114
|
+
/** First breaker trip since the last success, for `health.vcs`. */
|
|
2115
|
+
get trippedSince(): string | null;
|
|
1781
2116
|
/**
|
|
1782
|
-
* Begin accepting file changes
|
|
1783
|
-
*
|
|
1784
|
-
*
|
|
1785
|
-
* Performs startup orphan detection/recovery before starting the squash
|
|
1786
|
-
* manager, ensuring the repo is on the configured branch, and reports
|
|
1787
|
-
* (never clears) an abandoned cherry-pick, rebase, or merge.
|
|
1788
|
-
*
|
|
1789
|
-
* Baseline mode (commit prefix `"baseline:"`) remains active until
|
|
1790
|
-
* {@link endBaseline} is called by the coordinator after the initial scan.
|
|
2117
|
+
* Begin accepting file changes after startup maintenance under the lock
|
|
2118
|
+
* (never a checkout, D167); start the hourly sweep and squash. Baseline
|
|
2119
|
+
* mode lasts until {@link endBaseline}.
|
|
1791
2120
|
*/
|
|
1792
2121
|
start(): Promise<void>;
|
|
1793
|
-
/**
|
|
1794
|
-
* Signal that the initial filesystem scan is complete.
|
|
1795
|
-
* Clears the baseline flag so subsequent commits use normal "watcher: batch" messages.
|
|
1796
|
-
*/
|
|
2122
|
+
/** Initial scan done: later commits use `watcher: batch` messages. */
|
|
1797
2123
|
endBaseline(): void;
|
|
1798
2124
|
/**
|
|
1799
|
-
* Add a file to the pending set and start the throttle timer
|
|
1800
|
-
*
|
|
1801
|
-
*
|
|
1802
|
-
* The circuit breaker is intentionally not reset here: recovery is
|
|
2125
|
+
* Add a file to the pending set and start the throttle timer; a full set
|
|
2126
|
+
* commits at once. The breaker is intentionally not reset here: recovery is
|
|
1803
2127
|
* time-based, so a busy root cannot hammer a deterministic failure.
|
|
1804
2128
|
*
|
|
1805
2129
|
* @param filePath - Absolute path of the changed file.
|
|
1806
2130
|
*/
|
|
1807
2131
|
fileChanged(filePath: string): void;
|
|
1808
|
-
/**
|
|
1809
|
-
* Record reversion metadata so the next commit uses a revert-prefixed message.
|
|
1810
|
-
*
|
|
1811
|
-
* @param reversion - The reversion metadata to record.
|
|
1812
|
-
*/
|
|
2132
|
+
/** Record a reversion so the next commit uses a revert-prefixed message. */
|
|
1813
2133
|
addPendingReversion(reversion: PendingReversion): void;
|
|
1814
2134
|
/**
|
|
1815
2135
|
* Queue a deleted file. Staging records the deletion if git tracks it.
|
|
@@ -1817,66 +2137,31 @@ declare class VcsManager {
|
|
|
1817
2137
|
* @param filePath - Absolute path of the deleted file.
|
|
1818
2138
|
*/
|
|
1819
2139
|
handleUnlink(filePath: string): void;
|
|
1820
|
-
/**
|
|
1821
|
-
|
|
1822
|
-
|
|
1823
|
-
* Used by SquashManager to coordinate squash operations.
|
|
1824
|
-
*/
|
|
1825
|
-
pause(): Promise<void>;
|
|
1826
|
-
/**
|
|
1827
|
-
* Resume the commit pipeline after a pause.
|
|
1828
|
-
* Re-enables normal commit operations and starts a throttle timer
|
|
1829
|
-
* if there are pending files that accumulated during the pause.
|
|
1830
|
-
*/
|
|
1831
|
-
resume(): void;
|
|
1832
|
-
/**
|
|
1833
|
-
* Commit all pending files now, in batches of at most maxBatchSize.
|
|
1834
|
-
*/
|
|
2140
|
+
/** Push now; the caller holds {@link lock} (`/vcs/exclude`, D71). */
|
|
2141
|
+
pushInHold(): Promise<void>;
|
|
2142
|
+
/** Commit all pending files now, in batches of at most maxBatchSize. */
|
|
1835
2143
|
flush(): Promise<void>;
|
|
1836
|
-
/**
|
|
1837
|
-
* Stop accepting file changes, flush pending, and clean up timers.
|
|
1838
|
-
*/
|
|
2144
|
+
/** Stop accepting file changes, flush pending, and clean up timers. */
|
|
1839
2145
|
stop(): Promise<void>;
|
|
2146
|
+
/** Run a squash now (as the cron does); undefined when retention is off. */
|
|
2147
|
+
runSquash(): ReturnType<SquashManager['runSquash']> | undefined;
|
|
1840
2148
|
/**
|
|
1841
2149
|
* Add tracked-but-deleted paths (`git ls-files --deleted`) in this
|
|
1842
2150
|
* manager's watch scope to pending, so the next commit (typically the
|
|
1843
|
-
* baseline) records deletions
|
|
1844
|
-
* Called by the coordinator before flush/endBaseline on startup. See #249.
|
|
2151
|
+
* baseline) records deletions made while nothing was watching (#249).
|
|
1845
2152
|
*
|
|
1846
2153
|
* @param isInScope - Returns true if the absolute path routes to this
|
|
1847
2154
|
* manager (the coordinator's routing and watch-scope logic).
|
|
1848
2155
|
*/
|
|
1849
2156
|
reconcileDeletions(isInScope: (absolutePath: string) => boolean): Promise<void>;
|
|
1850
|
-
/** Take up to maxBatchSize files from the pending set. */
|
|
1851
|
-
private takeBatch;
|
|
1852
|
-
/** Chain a batch behind the in-flight commit, tracking it as backlog. */
|
|
1853
|
-
private enqueueBatch;
|
|
1854
|
-
/** Put files back in the pending set. Pending is a set, so this cannot grow it past the distinct paths seen. */
|
|
1855
|
-
private retain;
|
|
1856
|
-
private clearThrottle;
|
|
1857
2157
|
/**
|
|
1858
|
-
*
|
|
1859
|
-
*
|
|
1860
|
-
|
|
1861
|
-
|
|
1862
|
-
|
|
1863
|
-
/**
|
|
1864
|
-
* Ensure a timer will flush pending files when the breaker's cooldown
|
|
1865
|
-
* elapses, without needing a new file-change event.
|
|
1866
|
-
*/
|
|
1867
|
-
private scheduleBreakerRetry;
|
|
1868
|
-
/**
|
|
1869
|
-
* Commit a batch with index.lock retry, stale lock detection, pause
|
|
1870
|
-
* support, and the circuit breaker. A failed batch is always retained.
|
|
2158
|
+
* Commit a batch (the caller holds the lock) with index.lock retry,
|
|
2159
|
+
* stale lock removal and the circuit breaker. A failed batch is always
|
|
2160
|
+
* retained.
|
|
2161
|
+
*
|
|
2162
|
+
* @returns true on success (including "nothing staged").
|
|
1871
2163
|
*/
|
|
1872
2164
|
private commitBatch;
|
|
1873
|
-
/**
|
|
1874
|
-
* One commit attempt: stage, skip if nothing is staged, commit, push.
|
|
1875
|
-
*
|
|
1876
|
-
* @returns true if a commit was created; false for a no-op.
|
|
1877
|
-
*/
|
|
1878
|
-
private tryCommit;
|
|
1879
|
-
private onCommitSuccess;
|
|
1880
2165
|
private onCommitFailure;
|
|
1881
2166
|
}
|
|
1882
2167
|
|
|
@@ -1894,10 +2179,15 @@ declare class VcsCoordinator {
|
|
|
1894
2179
|
private readonly roots;
|
|
1895
2180
|
private readonly logger;
|
|
1896
2181
|
private readonly isInWatchScope;
|
|
1897
|
-
constructor(config: JeevesWatcherConfig, logger: pino.Logger);
|
|
1898
2182
|
/**
|
|
1899
|
-
*
|
|
1900
|
-
*
|
|
2183
|
+
* @param config - Config at construction (roots, remotes, retention).
|
|
2184
|
+
* @param logger - Logger.
|
|
2185
|
+
* @param getConfig - Live config, for settings read at each staging
|
|
2186
|
+
* (`vcs.maxFileBytes`, D67). Default: the construction config.
|
|
2187
|
+
*/
|
|
2188
|
+
constructor(config: JeevesWatcherConfig, logger: pino.Logger, getConfig?: () => JeevesWatcherConfig);
|
|
2189
|
+
/**
|
|
2190
|
+
* Start all VcsManager instances (each runs its startup maintenance).
|
|
1901
2191
|
*/
|
|
1902
2192
|
start(): Promise<void>;
|
|
1903
2193
|
/**
|
|
@@ -1920,6 +2210,12 @@ declare class VcsCoordinator {
|
|
|
1920
2210
|
* Flush all managers and clean up.
|
|
1921
2211
|
*/
|
|
1922
2212
|
stop(): Promise<void>;
|
|
2213
|
+
/**
|
|
2214
|
+
* VCS state for `GET /status` `health.vcs` (D86).
|
|
2215
|
+
*
|
|
2216
|
+
* @returns Root count, total backlog, tripped roots and the oldest trip.
|
|
2217
|
+
*/
|
|
2218
|
+
getHealth(): VcsHealth;
|
|
1923
2219
|
/**
|
|
1924
2220
|
* Get the sorted root paths (longest-first).
|
|
1925
2221
|
*/
|
|
@@ -1942,48 +2238,6 @@ declare class VcsCoordinator {
|
|
|
1942
2238
|
findManagerForPath(normalizedPath: string): VcsManager | undefined;
|
|
1943
2239
|
}
|
|
1944
2240
|
|
|
1945
|
-
/**
|
|
1946
|
-
* @module api/InitialScanTracker
|
|
1947
|
-
* Tracks initial filesystem scan state for status reporting.
|
|
1948
|
-
*/
|
|
1949
|
-
/** Initial scan status snapshot for API consumers. */
|
|
1950
|
-
interface InitialScanStatus {
|
|
1951
|
-
/** Whether the initial scan is currently in progress. */
|
|
1952
|
-
active: boolean;
|
|
1953
|
-
/** Number of files matched by watch globs. */
|
|
1954
|
-
filesMatched?: number;
|
|
1955
|
-
/** Number of files enqueued for processing so far. */
|
|
1956
|
-
filesEnqueued?: number;
|
|
1957
|
-
/** ISO 8601 timestamp when the scan started. */
|
|
1958
|
-
startedAt?: string;
|
|
1959
|
-
/** ISO 8601 timestamp when the scan completed. */
|
|
1960
|
-
completedAt?: string;
|
|
1961
|
-
/** Total scan duration in milliseconds. */
|
|
1962
|
-
durationMs?: number;
|
|
1963
|
-
}
|
|
1964
|
-
/**
|
|
1965
|
-
* Tracks the state of the initial filesystem scan after service start.
|
|
1966
|
-
*/
|
|
1967
|
-
declare class InitialScanTracker {
|
|
1968
|
-
private _active;
|
|
1969
|
-
private _filesMatched;
|
|
1970
|
-
private _filesEnqueued;
|
|
1971
|
-
private _startedAt?;
|
|
1972
|
-
private _completedAt?;
|
|
1973
|
-
private _durationMs?;
|
|
1974
|
-
private _started;
|
|
1975
|
-
/** Mark the initial scan as started. */
|
|
1976
|
-
start(): void;
|
|
1977
|
-
/** Set the total number of matched files. */
|
|
1978
|
-
setMatched(count: number): void;
|
|
1979
|
-
/** Increment the processed file count. */
|
|
1980
|
-
incrementEnqueued(): void;
|
|
1981
|
-
/** Mark the scan as complete. */
|
|
1982
|
-
complete(): void;
|
|
1983
|
-
/** Get current scan status. */
|
|
1984
|
-
getStatus(): InitialScanStatus;
|
|
1985
|
-
}
|
|
1986
|
-
|
|
1987
2241
|
/**
|
|
1988
2242
|
* @module health
|
|
1989
2243
|
* Tracks consecutive system-level failures and applies exponential backoff.
|
|
@@ -2039,12 +2293,265 @@ declare class SystemHealth {
|
|
|
2039
2293
|
* @param signal - Optional abort signal.
|
|
2040
2294
|
*/
|
|
2041
2295
|
backoff(signal?: AbortSignal): Promise<void>;
|
|
2296
|
+
/**
|
|
2297
|
+
* Run one operation with health tracking: back off, run it and record
|
|
2298
|
+
* the success, or record its failure.
|
|
2299
|
+
*
|
|
2300
|
+
* @param fn - The operation.
|
|
2301
|
+
* @returns False when the failure was fatal (the caller stops).
|
|
2302
|
+
* @throws When retries are exhausted and no fatal-error callback is set.
|
|
2303
|
+
*/
|
|
2304
|
+
run(fn: () => Promise<void>): Promise<boolean>;
|
|
2042
2305
|
/** Current consecutive failure count. */
|
|
2043
2306
|
get failures(): number;
|
|
2044
2307
|
}
|
|
2045
2308
|
|
|
2046
2309
|
/**
|
|
2047
|
-
*
|
|
2310
|
+
* @module watcher/changeSource/types
|
|
2311
|
+
* The change-source seam (spec Design 9, D120, D149): a `ChangeSource` supplies raw events and root signals to a `ChangeSink`; `FileSystemWatcher` implements the sink and owns every decision. Types only.
|
|
2312
|
+
*/
|
|
2313
|
+
|
|
2314
|
+
/** A classified event, as chokidar reports it. */
|
|
2315
|
+
type ClassifiedEventType = 'add' | 'change' | 'unlink' | 'addDir' | 'unlinkDir';
|
|
2316
|
+
/**
|
|
2317
|
+
* One unclassified event of a parcel batch (D149): an absolute path and a
|
|
2318
|
+
* type that is a hint only (`lstat` decides).
|
|
2319
|
+
*/
|
|
2320
|
+
interface RawChangeEvent {
|
|
2321
|
+
/** Absolute path. */
|
|
2322
|
+
path: string;
|
|
2323
|
+
/** Parcel's event type. */
|
|
2324
|
+
type: 'create' | 'update' | 'delete';
|
|
2325
|
+
}
|
|
2326
|
+
/**
|
|
2327
|
+
* Where a change source delivers events and signals. Implemented by
|
|
2328
|
+
* `FileSystemWatcher`, which owns classification, stability waits, pairing,
|
|
2329
|
+
* renewals and every reconcile trigger (D120).
|
|
2330
|
+
*/
|
|
2331
|
+
interface ChangeSink {
|
|
2332
|
+
/** A classified event (chokidar). */
|
|
2333
|
+
event: (type: ClassifiedEventType, path: string, stats?: Stats) => void;
|
|
2334
|
+
/** One whole parcel batch for a root, sorted by path (D149). */
|
|
2335
|
+
rawEvents: (root: string, events: RawChangeEvent[]) => void;
|
|
2336
|
+
/** The source finished its initial set for `root`. */
|
|
2337
|
+
initialScanDone: (root: string) => void;
|
|
2338
|
+
/** The source re-created `root`'s subscription after an error (D131). */
|
|
2339
|
+
resubscribed: (root: string) => void;
|
|
2340
|
+
/**
|
|
2341
|
+
* `root` became unreachable (D109), or is reachable but cannot be
|
|
2342
|
+
* watched (`reachable`, D156: it is still reconciled); `code` is the
|
|
2343
|
+
* error code.
|
|
2344
|
+
*/
|
|
2345
|
+
rootUnavailable: (root: string, code: string, options?: RootUnavailableOptions) => void;
|
|
2346
|
+
/** `root` is reachable again (D109). */
|
|
2347
|
+
rootAvailable: (root: string) => void;
|
|
2348
|
+
}
|
|
2349
|
+
/** Details of {@link ChangeSink.rootUnavailable}. */
|
|
2350
|
+
interface RootUnavailableOptions {
|
|
2351
|
+
/**
|
|
2352
|
+
* The root is still on disk but unwatched (a non-transient subscribe
|
|
2353
|
+
* failure, D156): it counts in `unavailableRoots` and is still
|
|
2354
|
+
* reconciled.
|
|
2355
|
+
*/
|
|
2356
|
+
reachable?: boolean;
|
|
2357
|
+
}
|
|
2358
|
+
|
|
2359
|
+
/**
|
|
2360
|
+
* @module api/InitialScanTracker
|
|
2361
|
+
* Tracks initial filesystem scan state for status reporting.
|
|
2362
|
+
*/
|
|
2363
|
+
|
|
2364
|
+
/**
|
|
2365
|
+
* Tracks the state of the initial filesystem scan after service start.
|
|
2366
|
+
*/
|
|
2367
|
+
declare class InitialScanTracker {
|
|
2368
|
+
private _active;
|
|
2369
|
+
private _filesMatched;
|
|
2370
|
+
private _filesEnqueued;
|
|
2371
|
+
private _startedAt?;
|
|
2372
|
+
private _completedAt?;
|
|
2373
|
+
private _durationMs?;
|
|
2374
|
+
private _started;
|
|
2375
|
+
/** Mark the initial scan as started. */
|
|
2376
|
+
start(): void;
|
|
2377
|
+
/** Set the total number of matched files. */
|
|
2378
|
+
setMatched(count: number): void;
|
|
2379
|
+
/** Increment the processed file count. */
|
|
2380
|
+
incrementEnqueued(): void;
|
|
2381
|
+
/** Mark the scan as complete. */
|
|
2382
|
+
complete(): void;
|
|
2383
|
+
/** Get current scan status. */
|
|
2384
|
+
getStatus(): InitialScanStatus;
|
|
2385
|
+
}
|
|
2386
|
+
|
|
2387
|
+
/**
|
|
2388
|
+
* @module watcher/fileEvents
|
|
2389
|
+
* What a filtered file event does: the VCS hook, move correlation and the processing queue. I/O: enqueues processor work.
|
|
2390
|
+
*/
|
|
2391
|
+
|
|
2392
|
+
/** VCS change callback. */
|
|
2393
|
+
type VcsFileChange = (filePath: string, event: 'add' | 'change' | 'unlink') => void;
|
|
2394
|
+
|
|
2395
|
+
/**
|
|
2396
|
+
* @module watcher/inventory/Inventory
|
|
2397
|
+
* `FileSystemWatcher`'s inventory (D99): the files that passed its filters, keyed by `normalizeDocumentKey`, with the child-set directory index (D127, D150). Pure.
|
|
2398
|
+
*/
|
|
2399
|
+
/** File size and modification time, as a walk or `stat` reports them. */
|
|
2400
|
+
interface FileStats {
|
|
2401
|
+
/** Size in bytes. */
|
|
2402
|
+
size: number;
|
|
2403
|
+
/** Modification time (ms since epoch). */
|
|
2404
|
+
mtimeMs: number;
|
|
2405
|
+
}
|
|
2406
|
+
/** One inventory entry. */
|
|
2407
|
+
interface InventoryEntry {
|
|
2408
|
+
/** The path as the source reported it. */
|
|
2409
|
+
path: string;
|
|
2410
|
+
/** Size, when the inventory tracks stats (parcel source). */
|
|
2411
|
+
size?: number;
|
|
2412
|
+
/** Modification time, when the inventory tracks stats. */
|
|
2413
|
+
mtimeMs?: number;
|
|
2414
|
+
}
|
|
2415
|
+
/**
|
|
2416
|
+
* The files the change source last saw that pass `FileSystemWatcher`'s
|
|
2417
|
+
* filters. Stats are stored only when `trackStats` is set (the parcel
|
|
2418
|
+
* source, whose initial set is the walk); under chokidar entries hold paths
|
|
2419
|
+
* only (spec Design 9).
|
|
2420
|
+
*/
|
|
2421
|
+
declare class Inventory {
|
|
2422
|
+
private readonly trackStats;
|
|
2423
|
+
private readonly entries;
|
|
2424
|
+
private readonly index;
|
|
2425
|
+
/** @param trackStats - Store size and mtime with each entry. */
|
|
2426
|
+
constructor(trackStats: boolean);
|
|
2427
|
+
/** Number of files. */
|
|
2428
|
+
get size(): number;
|
|
2429
|
+
/** Add or update a file. */
|
|
2430
|
+
set(path: string, stats?: FileStats): void;
|
|
2431
|
+
/**
|
|
2432
|
+
* Remove a file.
|
|
2433
|
+
*
|
|
2434
|
+
* @returns True when it was present.
|
|
2435
|
+
*/
|
|
2436
|
+
delete(path: string): boolean;
|
|
2437
|
+
/** The entry for a path, if present. */
|
|
2438
|
+
get(path: string): InventoryEntry | undefined;
|
|
2439
|
+
/**
|
|
2440
|
+
* Whether a path is a directory the inventory holds files under (D127:
|
|
2441
|
+
* an absent path is classified as a directory delete by this).
|
|
2442
|
+
*/
|
|
2443
|
+
isDirectory(path: string): boolean;
|
|
2444
|
+
/** Every file path, as the source reported it (`/walk`, D83). */
|
|
2445
|
+
paths(): string[];
|
|
2446
|
+
/**
|
|
2447
|
+
* The entries beneath a directory, at any depth, keyed by document key;
|
|
2448
|
+
* O(subtree size), never a scan of the inventory.
|
|
2449
|
+
*/
|
|
2450
|
+
entriesUnder(dir: string): Map<string, InventoryEntry>;
|
|
2451
|
+
}
|
|
2452
|
+
|
|
2453
|
+
/**
|
|
2454
|
+
* @module watcher/changeSource/parcelModule
|
|
2455
|
+
* Loading `@parcel/watcher` only when it is selected (D125): a cached dynamic import whose failure becomes a refusal naming the chokidar switch, the native-load error test, and the explicit backend per platform (D124). I/O: the import.
|
|
2456
|
+
*/
|
|
2457
|
+
|
|
2458
|
+
/** The parts of `@parcel/watcher` the parcel source uses. */
|
|
2459
|
+
type ParcelWatcherModule = Pick<typeof ParcelWatcher, 'subscribe'>;
|
|
2460
|
+
/** Imports the module (injectable for tests). */
|
|
2461
|
+
type ParcelImporter = () => Promise<ParcelWatcherModule>;
|
|
2462
|
+
|
|
2463
|
+
/**
|
|
2464
|
+
* @module watcher/changeSource/restart
|
|
2465
|
+
* The process-restart seam of D196: on Windows the parcel source never unsubscribes (`@parcel/watcher` 2.6.0 crashes the process natively there), so a watcher rebuild or a subscription recovery exits the process for the service manager to restart it. The app implements the graceful restarter; `exitingRestarter` is the fallback for a watcher built without the app. I/O: `process.exit` in that fallback only.
|
|
2466
|
+
*/
|
|
2467
|
+
|
|
2468
|
+
/** One request to exit for a restart. */
|
|
2469
|
+
interface RestartRequest {
|
|
2470
|
+
/** The cause (a code, no path: it reaches health, D89). */
|
|
2471
|
+
cause: RestartCause;
|
|
2472
|
+
/** The root concerned, for the log line only. */
|
|
2473
|
+
root?: string;
|
|
2474
|
+
/** The error behind it, for the log line only. */
|
|
2475
|
+
err?: unknown;
|
|
2476
|
+
/**
|
|
2477
|
+
* A config reload's reindex scope (`configWatch.reindex`), run by the
|
|
2478
|
+
* restarted process instead of this one.
|
|
2479
|
+
*/
|
|
2480
|
+
reindex?: ConfigWatchReindexScope;
|
|
2481
|
+
}
|
|
2482
|
+
/**
|
|
2483
|
+
* Exits the process for a service-manager restart (D196). `restart`
|
|
2484
|
+
* returns at once: the exit follows a graceful stop, so callers inside the
|
|
2485
|
+
* change source's queue never wait on themselves. Only the first request
|
|
2486
|
+
* of a process counts. Injected, so tests never call `process.exit`.
|
|
2487
|
+
*/
|
|
2488
|
+
interface ProcessRestarter {
|
|
2489
|
+
/** Log the cause, stop gracefully, then exit with code 75 (`EX_TEMPFAIL`). */
|
|
2490
|
+
restart: (request: RestartRequest) => void;
|
|
2491
|
+
}
|
|
2492
|
+
|
|
2493
|
+
/**
|
|
2494
|
+
* @module watcher/ChangeSourceHealthTracker
|
|
2495
|
+
* `health.changeSource` (D133, D157): counters since start, owned by the app so they survive watcher rebuilds, plus the cause of the exit for a restart this process started after (D196). Pure.
|
|
2496
|
+
*/
|
|
2497
|
+
|
|
2498
|
+
/**
|
|
2499
|
+
* Counts and timestamps behind `health.changeSource`. Never holds a path in
|
|
2500
|
+
* its snapshot (D89).
|
|
2501
|
+
*/
|
|
2502
|
+
declare class ChangeSourceHealthTracker {
|
|
2503
|
+
private source;
|
|
2504
|
+
private resubscribes;
|
|
2505
|
+
private renewFailures;
|
|
2506
|
+
private reconcileEvents;
|
|
2507
|
+
private reconcileErrors;
|
|
2508
|
+
private lastReconcileAt;
|
|
2509
|
+
private lastReconcileDurationMs;
|
|
2510
|
+
private lastRenewDurationMs;
|
|
2511
|
+
private lastRestart;
|
|
2512
|
+
private readonly unavailable;
|
|
2513
|
+
private pendingStability;
|
|
2514
|
+
/** Record the running source and its pending-stability reader. */
|
|
2515
|
+
attach(source: ChangeSourceHealth['source'], pending: () => number): void;
|
|
2516
|
+
/** A subscription was re-created after an error (D131). */
|
|
2517
|
+
recordResubscribe(): void;
|
|
2518
|
+
/**
|
|
2519
|
+
* A renewal forced a source rebuild (D165), or rejected inside one
|
|
2520
|
+
* (D176).
|
|
2521
|
+
*
|
|
2522
|
+
* @param count - Failures to add (default 1).
|
|
2523
|
+
*/
|
|
2524
|
+
recordRenewFailure(count?: number): void;
|
|
2525
|
+
/** A subscription renewal finished (Linux parcel, D129, D157). */
|
|
2526
|
+
recordRenew(durationMs: number): void;
|
|
2527
|
+
/**
|
|
2528
|
+
* The previous process exited for a restart (D196): its cause and when.
|
|
2529
|
+
*
|
|
2530
|
+
* @param restart - The record it left.
|
|
2531
|
+
*/
|
|
2532
|
+
recordRestart(restart: {
|
|
2533
|
+
cause: RestartCause;
|
|
2534
|
+
at: string;
|
|
2535
|
+
}): void;
|
|
2536
|
+
/** Mark a root unavailable (D109) or available again. */
|
|
2537
|
+
setUnavailable(root: string, unavailable: boolean): void;
|
|
2538
|
+
/** Synthetic events a reconcile emitted (D90). */
|
|
2539
|
+
recordReconcileEvents(count: number): void;
|
|
2540
|
+
/** A reconcile finished (walk and compare). */
|
|
2541
|
+
recordReconcile(durationMs: number, at: Date): void;
|
|
2542
|
+
/** A reconcile errored and emitted nothing (D90). */
|
|
2543
|
+
recordReconcileError(): void;
|
|
2544
|
+
/** The `health.changeSource` body. */
|
|
2545
|
+
snapshot(): ChangeSourceHealth;
|
|
2546
|
+
}
|
|
2547
|
+
|
|
2548
|
+
/**
|
|
2549
|
+
* @module watcher/running
|
|
2550
|
+
* What one `FileSystemWatcher.start` builds: the change source (parcel or chokidar, D125), filters, inventory, filtered handlers, queue actions and, for parcel, the batch pipeline, wired together. Pure apart from constructing the source (not started here).
|
|
2551
|
+
*/
|
|
2552
|
+
|
|
2553
|
+
/**
|
|
2554
|
+
* Options for `FileSystemWatcher` beyond basic config.
|
|
2048
2555
|
*/
|
|
2049
2556
|
interface FileSystemWatcherOptions {
|
|
2050
2557
|
/** Maximum consecutive system-level failures before fatal error. */
|
|
@@ -2060,27 +2567,75 @@ interface FileSystemWatcherOptions {
|
|
|
2060
2567
|
/** Optional content hash cache for move detection. */
|
|
2061
2568
|
contentHashCache?: ContentHashCache;
|
|
2062
2569
|
/** Optional callback for VCS file change notifications. */
|
|
2063
|
-
onVcsFileChange?:
|
|
2064
|
-
/**
|
|
2065
|
-
|
|
2570
|
+
onVcsFileChange?: VcsFileChange;
|
|
2571
|
+
/**
|
|
2572
|
+
* Optional callback invoked when the initial filesystem scan completes,
|
|
2573
|
+
* with the index check's view of the watcher that completed it (D197).
|
|
2574
|
+
*/
|
|
2575
|
+
onInitialScanComplete?: (view: IndexCheckView) => void | Promise<void>;
|
|
2576
|
+
/** `health.changeSource` counters (D133), owned by the app across rebuilds. */
|
|
2577
|
+
changeSourceHealth?: ChangeSourceHealthTracker;
|
|
2578
|
+
/** Live `watch.reconcileIntervalMs` (D111), read at each scheduling. */
|
|
2579
|
+
getReconcileIntervalMs?: () => number | undefined;
|
|
2580
|
+
/** Imports `@parcel/watcher` (tests; default the real module, D125). */
|
|
2581
|
+
importParcel?: ParcelImporter;
|
|
2582
|
+
/** The service state directory (the parcel rebuild sentinel, D165). */
|
|
2583
|
+
stateDir?: string;
|
|
2584
|
+
/**
|
|
2585
|
+
* Exits for a service-manager restart where parcel never unsubscribes
|
|
2586
|
+
* (Windows, D196); default an immediate exit.
|
|
2587
|
+
*/
|
|
2588
|
+
restarter?: ProcessRestarter;
|
|
2589
|
+
}
|
|
2590
|
+
|
|
2591
|
+
/**
|
|
2592
|
+
* @module watcher/indexCheck/view
|
|
2593
|
+
* What the index check at start (D197) reads from a running `FileSystemWatcher`: its roots, why a root must be skipped (unavailable D109, unwatched D156, start walk failed) and whether the inventory holds a path. Pure.
|
|
2594
|
+
*/
|
|
2595
|
+
|
|
2596
|
+
/** Why a root is not checked (besides being gone at check time). */
|
|
2597
|
+
type IndexCheckSkipReason = 'unavailable' | 'unwatched' | 'walkFailed';
|
|
2598
|
+
/** The running watcher as the index check sees it. */
|
|
2599
|
+
interface IndexCheckView {
|
|
2600
|
+
/** The resolved watch roots, nested ones collapsed (D195 case). */
|
|
2601
|
+
roots: readonly string[];
|
|
2602
|
+
/**
|
|
2603
|
+
* Why the root must be skipped, or undefined when it can be checked.
|
|
2604
|
+
*
|
|
2605
|
+
* @param root - One of {@link IndexCheckView.roots}.
|
|
2606
|
+
*/
|
|
2607
|
+
skipReason: (root: string) => IndexCheckSkipReason | undefined;
|
|
2608
|
+
/**
|
|
2609
|
+
* Whether the inventory holds the file (its point-ID key form).
|
|
2610
|
+
*
|
|
2611
|
+
* @param path - A file path.
|
|
2612
|
+
*/
|
|
2613
|
+
has: (path: string) => boolean;
|
|
2614
|
+
/** Whether this running state is still the watcher's (no stop or rebuild). */
|
|
2615
|
+
live: () => boolean;
|
|
2066
2616
|
}
|
|
2617
|
+
|
|
2067
2618
|
/**
|
|
2068
|
-
*
|
|
2619
|
+
* @module watcher
|
|
2620
|
+
* Filesystem watcher: drives a change source (parcel or chokidar, D125) through the `ChangeSink` seam, filters its events, keeps the inventory and enqueues processing. I/O: watches files, enqueues processor work.
|
|
2069
2621
|
*/
|
|
2070
|
-
|
|
2622
|
+
|
|
2623
|
+
/**
|
|
2624
|
+
* Filesystem watcher. A change source only reports events (D120); this
|
|
2625
|
+
* class filters them, keeps the inventory (D99) and maps them to the
|
|
2626
|
+
* processing queue.
|
|
2627
|
+
*/
|
|
2628
|
+
declare class FileSystemWatcher implements ChangeSink {
|
|
2071
2629
|
private readonly config;
|
|
2072
2630
|
private readonly queue;
|
|
2073
2631
|
private readonly processor;
|
|
2074
2632
|
private readonly logger;
|
|
2633
|
+
private readonly options;
|
|
2075
2634
|
private readonly health;
|
|
2076
|
-
private
|
|
2077
|
-
|
|
2078
|
-
private
|
|
2079
|
-
private
|
|
2080
|
-
private readonly onInitialScanComplete?;
|
|
2081
|
-
private moveCorrelator?;
|
|
2082
|
-
private globMatches;
|
|
2083
|
-
private watcher;
|
|
2635
|
+
private running;
|
|
2636
|
+
/** A stopped source left its watches live (D196). */
|
|
2637
|
+
private leftWatches;
|
|
2638
|
+
private initialScanComplete;
|
|
2084
2639
|
/**
|
|
2085
2640
|
* Create a new FileSystemWatcher.
|
|
2086
2641
|
*
|
|
@@ -2092,36 +2647,64 @@ declare class FileSystemWatcher {
|
|
|
2092
2647
|
*/
|
|
2093
2648
|
constructor(config: WatchConfig, queue: EventQueue, processor: DocumentProcessorInterface, logger: pino.Logger, options?: FileSystemWatcherOptions);
|
|
2094
2649
|
/**
|
|
2095
|
-
* Start watching the filesystem and processing events.
|
|
2096
|
-
|
|
2097
|
-
start(): void;
|
|
2098
|
-
/**
|
|
2099
|
-
* Get the list of all currently watched file paths (absolute).
|
|
2650
|
+
* Start watching the filesystem and processing events. With parcel the
|
|
2651
|
+
* roots are subscribed first, then walked in the background (D58).
|
|
2100
2652
|
*
|
|
2101
|
-
*
|
|
2102
|
-
* Returns an empty array if the watcher hasn't been started.
|
|
2653
|
+
* @throws ChangeSourceLoadError when parcel is selected and cannot load.
|
|
2103
2654
|
*/
|
|
2104
|
-
|
|
2105
|
-
/**
|
|
2106
|
-
|
|
2655
|
+
start(): Promise<void>;
|
|
2656
|
+
/** A classified event from the change source (chokidar), with the stats it read, if any. */
|
|
2657
|
+
event(type: ClassifiedEventType, path: string, stats?: Stats): void;
|
|
2658
|
+
/**
|
|
2659
|
+
* The directory-create handler (D91, D120): reconcile a directory created
|
|
2660
|
+
* after the initial scan, so files written into it before its watch was
|
|
2661
|
+
* set up are not missed. The reconciler drops it before the scan ends.
|
|
2662
|
+
*/
|
|
2663
|
+
private directoryCreated;
|
|
2664
|
+
/** Start a reconcile of `dir` (every trigger is owned here, D120). */
|
|
2665
|
+
private reconcile;
|
|
2666
|
+
/**
|
|
2667
|
+
* A raw parcel batch (D149): into the FIFO, classified from the disk and
|
|
2668
|
+
* applied in order.
|
|
2669
|
+
*/
|
|
2670
|
+
rawEvents(root: string, events: RawChangeEvent[]): void;
|
|
2671
|
+
/** The source finished its initial set for a root; the scan completes when every root has. */
|
|
2672
|
+
initialScanDone(sourceRoot: string): void;
|
|
2673
|
+
/** The source re-created a root's subscription after an error (D131). */
|
|
2674
|
+
resubscribed(sourceRoot: string): void;
|
|
2675
|
+
/** A root is unreachable (D109), or reachable but unwatched (D156). */
|
|
2676
|
+
rootUnavailable(sourceRoot: string, code: string, options?: RootUnavailableOptions): void;
|
|
2677
|
+
/** A root is reachable again (D109). */
|
|
2678
|
+
rootAvailable(sourceRoot: string): void;
|
|
2679
|
+
/** A root signal's context (the canonical root), or undefined when not running. */
|
|
2680
|
+
private signal;
|
|
2681
|
+
/**
|
|
2682
|
+
* The inventory's file paths (absolute, as the source reported them):
|
|
2683
|
+
* matched files only, never directories or filtered files (D83). No
|
|
2684
|
+
* filesystem I/O; empty before start.
|
|
2107
2685
|
*/
|
|
2686
|
+
getWatchedFiles(): string[];
|
|
2687
|
+
/** Whether the initial filesystem scan is complete. */
|
|
2108
2688
|
get isReady(): boolean;
|
|
2109
2689
|
/**
|
|
2110
|
-
*
|
|
2690
|
+
* Whether a rebuild must exit for a restart (D196): the running source,
|
|
2691
|
+
* or one this watcher stopped (its watches stay live), cannot release
|
|
2692
|
+
* its watches in-process (parcel on Windows).
|
|
2111
2693
|
*/
|
|
2694
|
+
get restartsToRebuild(): boolean;
|
|
2695
|
+
/** The running watcher's inventory (D99), undefined before start. */
|
|
2696
|
+
get inventory(): Inventory | undefined;
|
|
2697
|
+
/** What the index check at start reads (D197); undefined before start. */
|
|
2698
|
+
get indexCheckView(): IndexCheckView | undefined;
|
|
2699
|
+
/** Stop the filesystem watcher. */
|
|
2112
2700
|
stop(): Promise<void>;
|
|
2113
|
-
/**
|
|
2114
|
-
* Get the system health tracker.
|
|
2115
|
-
*/
|
|
2701
|
+
/** Get the system health tracker. */
|
|
2116
2702
|
get systemHealth(): SystemHealth;
|
|
2117
2703
|
/**
|
|
2118
|
-
*
|
|
2119
|
-
|
|
2120
|
-
private isGitignored;
|
|
2121
|
-
/**
|
|
2122
|
-
* If the changed file is a `.gitignore`, invalidate the filter cache.
|
|
2704
|
+
* Re-arm the periodic reconcile timers with the live interval: a reload
|
|
2705
|
+
* that changed only `watch.reconcileIntervalMs` needs no rebuild (D111).
|
|
2123
2706
|
*/
|
|
2124
|
-
|
|
2707
|
+
refreshReconcileSchedule(): void;
|
|
2125
2708
|
/**
|
|
2126
2709
|
* Wrap a processing operation with health tracking.
|
|
2127
2710
|
* On success, resets the failure counter.
|
|
@@ -2134,19 +2717,7 @@ declare class FileSystemWatcher {
|
|
|
2134
2717
|
* @module api/ReindexTracker
|
|
2135
2718
|
* Tracks reindex operation state for status reporting. Single instance shared across handlers.
|
|
2136
2719
|
*/
|
|
2137
|
-
|
|
2138
|
-
interface ReindexStatus {
|
|
2139
|
-
/** Whether a reindex operation is currently in progress. */
|
|
2140
|
-
active: boolean;
|
|
2141
|
-
/** The active reindex scope (when {@link active} is true). */
|
|
2142
|
-
scope?: string;
|
|
2143
|
-
/** ISO 8601 timestamp when the current reindex started (when {@link active} is true). */
|
|
2144
|
-
startedAt?: string;
|
|
2145
|
-
/** Number of files processed so far (when {@link active} is true). */
|
|
2146
|
-
filesProcessed?: number;
|
|
2147
|
-
/** Total number of files to process (when {@link active} is true). */
|
|
2148
|
-
totalFiles?: number;
|
|
2149
|
-
}
|
|
2720
|
+
|
|
2150
2721
|
/**
|
|
2151
2722
|
* Tracks the state of reindex operations.
|
|
2152
2723
|
*/
|
|
@@ -2209,33 +2780,56 @@ interface ApiServerOptions {
|
|
|
2209
2780
|
configPath: string;
|
|
2210
2781
|
/** Helper introspection for merged document. */
|
|
2211
2782
|
helperIntrospection?: AllHelpersIntrospection;
|
|
2212
|
-
/** Virtual rule store for externally registered inference rules
|
|
2213
|
-
|
|
2783
|
+
/** Virtual rule store for externally registered inference rules (the
|
|
2784
|
+
* `/rules/*` routes). */
|
|
2785
|
+
virtualRuleStore: VirtualRuleStore;
|
|
2214
2786
|
/** Gitignore filter for reindex path validation. */
|
|
2215
2787
|
gitignoreFilter?: GitignoreFilter;
|
|
2216
2788
|
/** Service version string for /status endpoint. */
|
|
2217
2789
|
version?: string;
|
|
2218
2790
|
/** Initial scan tracker for /status visibility. */
|
|
2219
2791
|
initialScanTracker?: InitialScanTracker;
|
|
2220
|
-
/** Filesystem watcher instance for /walk endpoint (
|
|
2792
|
+
/** Filesystem watcher instance for /walk endpoint (its inventory, D83). */
|
|
2221
2793
|
fileSystemWatcher?: FileSystemWatcher;
|
|
2222
2794
|
/** Getter for live filesystem watcher access after hot-reload rebuilds. */
|
|
2223
2795
|
getFileSystemWatcher?: () => FileSystemWatcher | undefined;
|
|
2224
2796
|
/** Optional enrichment store for persisted enrichment metadata. */
|
|
2225
2797
|
enrichmentStore?: EnrichmentStoreInterface;
|
|
2226
|
-
/** VCS coordinator for git-backed versioning
|
|
2798
|
+
/** VCS coordinator for the git-backed versioning (`/vcs/*`) routes; without
|
|
2799
|
+
* it they answer as unregistered (`api/featureGates`). */
|
|
2227
2800
|
vcsCoordinator?: VcsCoordinator;
|
|
2801
|
+
/**
|
|
2802
|
+
* Longest document-lock wait of `POST /metadata`, `POST /rules/reapply`
|
|
2803
|
+
* and `POST /documents/delete` (default 10 s, D118; tests only).
|
|
2804
|
+
*/
|
|
2805
|
+
documentLockWaitMs?: number;
|
|
2806
|
+
/** Embedding health (`GET /status` `health.embedding`, D88). */
|
|
2807
|
+
embeddingHealth?: {
|
|
2808
|
+
snapshot: () => EmbeddingHealthSnapshot;
|
|
2809
|
+
};
|
|
2810
|
+
/** Change-source health (`GET /status` `health.changeSource`, D133). */
|
|
2811
|
+
changeSourceHealth?: {
|
|
2812
|
+
snapshot: () => ChangeSourceHealth;
|
|
2813
|
+
};
|
|
2814
|
+
/** Index check at start (`health.indexCheck`, D197). */
|
|
2815
|
+
indexCheckHealth?: {
|
|
2816
|
+
snapshot: () => IndexCheckHealth;
|
|
2817
|
+
};
|
|
2228
2818
|
}
|
|
2229
2819
|
|
|
2230
2820
|
/**
|
|
2231
2821
|
* @module api
|
|
2232
|
-
* Fastify API server factory. Registers
|
|
2822
|
+
* Fastify API server factory. Registers every `WATCHER_CATALOG` route (plus `GET /openapi.json`) from the catalog, and returns an unstarted server instance.
|
|
2233
2823
|
*/
|
|
2234
2824
|
|
|
2235
2825
|
/**
|
|
2236
2826
|
* Create the Fastify API server with all routes registered.
|
|
2237
2827
|
*
|
|
2238
|
-
* The returned instance is not yet listening; call `server.listen()` to
|
|
2828
|
+
* The returned instance is not yet listening; call `server.listen()` to
|
|
2829
|
+
* start. The catalog routes are registered in a child plugin, so a
|
|
2830
|
+
* registration error surfaces from `ready()` or `listen()` (spec #281 D29).
|
|
2831
|
+
* The `/vcs/*` routes answer as unregistered unless a `vcsCoordinator` is
|
|
2832
|
+
* given (`api/featureGates`).
|
|
2239
2833
|
*
|
|
2240
2834
|
* @param options - The server options.
|
|
2241
2835
|
* @returns A configured Fastify instance.
|
|
@@ -2279,17 +2873,37 @@ interface LoadConfigOptions {
|
|
|
2279
2873
|
declare function loadConfig(configPath?: string, options?: LoadConfigOptions): Promise<JeevesWatcherConfig>;
|
|
2280
2874
|
|
|
2281
2875
|
/**
|
|
2282
|
-
*
|
|
2283
|
-
*
|
|
2284
|
-
*/
|
|
2285
|
-
|
|
2286
|
-
/**
|
|
2287
|
-
* Create a pino logger instance.
|
|
2876
|
+
* Create a pino logger. With `logging.file`, the file is open (or the
|
|
2877
|
+
* call rejects) before the logger is returned, so no early line is lost.
|
|
2288
2878
|
*
|
|
2289
2879
|
* @param config - Optional logging configuration.
|
|
2290
2880
|
* @returns A configured pino logger.
|
|
2291
2881
|
*/
|
|
2292
|
-
declare function createLogger(config?: LoggingConfig): pino.Logger
|
|
2882
|
+
declare function createLogger(config?: LoggingConfig): Promise<pino.Logger>;
|
|
2883
|
+
|
|
2884
|
+
/**
|
|
2885
|
+
* @module app/processRestarter
|
|
2886
|
+
* The app's exit for a service-manager restart (D196): log the cause, leave a restart record in the state directory, stop gracefully (with a hard deadline), then exit with `RESTART_EXIT_CODE`; at the next start, read the record, report it in `health.changeSource` (the app runs any deferred config reindex) and clear it once the start succeeded. I/O: the record file, a timer, `process.exit`.
|
|
2887
|
+
*/
|
|
2888
|
+
|
|
2889
|
+
/** What `createProcessRestarter` needs from the app. */
|
|
2890
|
+
interface ProcessRestarterDeps {
|
|
2891
|
+
/** The state directory (the record goes there). */
|
|
2892
|
+
stateDir: string;
|
|
2893
|
+
/** The app's logger, once it exists. */
|
|
2894
|
+
logger: () => pino.Logger | undefined;
|
|
2895
|
+
/** The app's graceful stop. */
|
|
2896
|
+
stop: () => Promise<void>;
|
|
2897
|
+
/**
|
|
2898
|
+
* The longest the graceful stop may take before the process exits
|
|
2899
|
+
* anyway: some stop steps (a hung `lstat` or git call) have no timeout.
|
|
2900
|
+
*/
|
|
2901
|
+
deadlineMs: number;
|
|
2902
|
+
/** `process.exit` (tests). */
|
|
2903
|
+
exit?: (code: number) => void;
|
|
2904
|
+
/** The clock (tests). */
|
|
2905
|
+
now?: () => Date;
|
|
2906
|
+
}
|
|
2293
2907
|
|
|
2294
2908
|
/**
|
|
2295
2909
|
* @module app/factories
|
|
@@ -2323,6 +2937,13 @@ interface JeevesWatcherFactories {
|
|
|
2323
2937
|
createFileSystemWatcher: (config: JeevesWatcherConfig['watch'], queue: EventQueue, processor: DocumentProcessorInterface, logger: pino.Logger, options?: FileSystemWatcherOptions) => FileSystemWatcher;
|
|
2324
2938
|
/** Create the HTTP API server. */
|
|
2325
2939
|
createApiServer: typeof createApiServer;
|
|
2940
|
+
/** Import `@parcel/watcher` when it is the selected source (D125). */
|
|
2941
|
+
importParcel: ParcelImporter;
|
|
2942
|
+
/**
|
|
2943
|
+
* The exit for a service-manager restart (D196). Tests replace it, so
|
|
2944
|
+
* they never call `process.exit`.
|
|
2945
|
+
*/
|
|
2946
|
+
createProcessRestarter: (deps: ProcessRestarterDeps) => ProcessRestarter;
|
|
2326
2947
|
}
|
|
2327
2948
|
|
|
2328
2949
|
/**
|
|
@@ -2369,9 +2990,7 @@ declare function startFromConfig(configPath?: string, descriptor?: JeevesCompone
|
|
|
2369
2990
|
* Main application orchestrator. Wires components, manages lifecycle (start/stop/reload).
|
|
2370
2991
|
*/
|
|
2371
2992
|
|
|
2372
|
-
/**
|
|
2373
|
-
* Main application class that wires together all components.
|
|
2374
|
-
*/
|
|
2993
|
+
/** Main application class that wires together all components. */
|
|
2375
2994
|
declare class JeevesWatcher {
|
|
2376
2995
|
private config;
|
|
2377
2996
|
private readonly configPath?;
|
|
@@ -2385,34 +3004,33 @@ declare class JeevesWatcher {
|
|
|
2385
3004
|
private server;
|
|
2386
3005
|
private processor;
|
|
2387
3006
|
private configWatcher;
|
|
2388
|
-
private
|
|
2389
|
-
private valuesManager;
|
|
3007
|
+
private stores;
|
|
2390
3008
|
private helperIntrospection;
|
|
2391
3009
|
private readonly virtualRuleStore;
|
|
2392
3010
|
private vectorStore;
|
|
2393
3011
|
private embeddingProvider;
|
|
3012
|
+
private embeddingHealth;
|
|
2394
3013
|
private gitignoreFilter;
|
|
2395
|
-
private enrichmentStore;
|
|
2396
|
-
private contentHashCache;
|
|
2397
3014
|
private vcsCoordinator;
|
|
2398
3015
|
private readonly initialScanTracker;
|
|
3016
|
+
private readonly changeSourceHealth;
|
|
3017
|
+
private readonly indexCheck;
|
|
3018
|
+
private readonly restarter;
|
|
3019
|
+
/** The state directory (default `ROOT_DEFAULTS.stateDir`). */
|
|
3020
|
+
private readonly stateDir;
|
|
2399
3021
|
private readonly version;
|
|
2400
3022
|
/** Create a new JeevesWatcher instance. */
|
|
2401
3023
|
constructor(config: JeevesWatcherConfig, configPath?: string, descriptor?: JeevesComponentDescriptor, factories?: Partial<JeevesWatcherFactories>, runtimeOptions?: JeevesWatcherRuntimeOptions);
|
|
2402
3024
|
/** Start the watcher, API server, and all components. */
|
|
2403
3025
|
start(): Promise<void>;
|
|
2404
|
-
/** Set up logger, VCS, embedding provider, and vector store. */
|
|
2405
|
-
private initInfrastructure;
|
|
2406
3026
|
/** Build the processing pipeline: rules, templates, processor, queue, VCS. */
|
|
2407
3027
|
private initPipeline;
|
|
2408
3028
|
/** Wire up watcher and VCS coordinator, then start all services. */
|
|
2409
3029
|
private startServicesAndWatcher;
|
|
2410
|
-
/**
|
|
2411
|
-
* Gracefully stop all components: the API server closes first (no new
|
|
2412
|
-
* notifications), then producers stop and queues drain (see
|
|
2413
|
-
* shutdownComponents).
|
|
2414
|
-
*/
|
|
3030
|
+
/** Gracefully stop: API server first (no new notifications), then producers, then queues drain (shutdownComponents). */
|
|
2415
3031
|
stop(): Promise<void>;
|
|
3032
|
+
/** Wiring every watcher the app builds shares, across rebuilds. */
|
|
3033
|
+
private watcherWiring;
|
|
2416
3034
|
private apiServerOptions;
|
|
2417
3035
|
private reloadConfig;
|
|
2418
3036
|
}
|
|
@@ -2487,112 +3105,5 @@ interface ResolvedWatchRoot {
|
|
|
2487
3105
|
relativePath: string;
|
|
2488
3106
|
}
|
|
2489
3107
|
|
|
2490
|
-
|
|
2491
|
-
|
|
2492
|
-
* Handles scheduled squash retention for git-backed VCS roots.
|
|
2493
|
-
*/
|
|
2494
|
-
|
|
2495
|
-
/** Result of a squash operation. */
|
|
2496
|
-
interface SquashResult {
|
|
2497
|
-
squashed: boolean;
|
|
2498
|
-
commitsRemoved?: number;
|
|
2499
|
-
commitsRetained?: number;
|
|
2500
|
-
error?: string;
|
|
2501
|
-
}
|
|
2502
|
-
/** Commit metadata for retention calculation. */
|
|
2503
|
-
interface CommitInfo {
|
|
2504
|
-
hash: string;
|
|
2505
|
-
date: Date;
|
|
2506
|
-
}
|
|
2507
|
-
/** Options for SquashManager construction beyond the required params. */
|
|
2508
|
-
interface SquashManagerOptions {
|
|
2509
|
-
/** Git branch name for squash operations. Default: "master". */
|
|
2510
|
-
branch?: string;
|
|
2511
|
-
/** Called before squash to drain and pause the commit pipeline. */
|
|
2512
|
-
pauseCommits?: () => Promise<void>;
|
|
2513
|
-
/** Called after squash to resume the commit pipeline. */
|
|
2514
|
-
resumeCommits?: () => void;
|
|
2515
|
-
/** Remote URL for force-push after squash. */
|
|
2516
|
-
remoteUrl?: string;
|
|
2517
|
-
/** Access token for HTTPS push authentication. */
|
|
2518
|
-
accessToken?: string;
|
|
2519
|
-
}
|
|
2520
|
-
/**
|
|
2521
|
-
* Manages scheduled squash retention for a single VCS root.
|
|
2522
|
-
*
|
|
2523
|
-
* Runs on a cron schedule (checked every 60s). When triggered, squashes
|
|
2524
|
-
* commits older than the retention boundary (the tighter of maxAgeDays
|
|
2525
|
-
* and maxVersions) into a single "historical baseline" orphan commit,
|
|
2526
|
-
* then cherry-picks retained commits on top. Force-pushes to remote
|
|
2527
|
-
* if configured (D13).
|
|
2528
|
-
*/
|
|
2529
|
-
declare class SquashManager {
|
|
2530
|
-
private readonly rootPath;
|
|
2531
|
-
private readonly retention;
|
|
2532
|
-
private readonly branch;
|
|
2533
|
-
private readonly pauseCommits;
|
|
2534
|
-
private readonly resumeCommits;
|
|
2535
|
-
private readonly remoteUrl;
|
|
2536
|
-
private readonly accessToken;
|
|
2537
|
-
private readonly logger;
|
|
2538
|
-
private intervalTimer;
|
|
2539
|
-
private running;
|
|
2540
|
-
constructor(rootPath: string, retention: VcsRetentionConfig, logger: pino.Logger, options?: SquashManagerOptions);
|
|
2541
|
-
/**
|
|
2542
|
-
* Start the cron-based squash scheduler.
|
|
2543
|
-
* Checks every 60 seconds if the cron expression matches.
|
|
2544
|
-
*/
|
|
2545
|
-
start(): void;
|
|
2546
|
-
/**
|
|
2547
|
-
* Stop the cron scheduler.
|
|
2548
|
-
*/
|
|
2549
|
-
stop(): void;
|
|
2550
|
-
/**
|
|
2551
|
-
* Run the squash operation. Exposed publicly for testing.
|
|
2552
|
-
*
|
|
2553
|
-
* Coordinates with VcsManager by calling pause/resume callbacks
|
|
2554
|
-
* to drain and suspend the commit pipeline during the squash.
|
|
2555
|
-
*/
|
|
2556
|
-
runSquash(): Promise<SquashResult>;
|
|
2557
|
-
/**
|
|
2558
|
-
* Refuse to start a multi-step history rewrite while another git
|
|
2559
|
-
* operation holds the index or an abandoned cherry-pick, rebase, or merge
|
|
2560
|
-
* is present (#249: report only, never auto-clear).
|
|
2561
|
-
*
|
|
2562
|
-
* @returns The refusal reason, or undefined if the squash may proceed.
|
|
2563
|
-
*/
|
|
2564
|
-
private checkRepoPreconditions;
|
|
2565
|
-
/**
|
|
2566
|
-
* Get all commits in chronological order (oldest first).
|
|
2567
|
-
*/
|
|
2568
|
-
getCommitLog(): Promise<CommitInfo[]>;
|
|
2569
|
-
/**
|
|
2570
|
-
* Calculate the retention boundary index.
|
|
2571
|
-
* Returns the index of the oldest commit to KEEP.
|
|
2572
|
-
* All commits before this index will be squashed into a baseline.
|
|
2573
|
-
*
|
|
2574
|
-
* Strategy: find the tighter constraint between age and count.
|
|
2575
|
-
* - Age: keep commits newer than maxAgeDays
|
|
2576
|
-
* - Count: keep the last maxVersions commits
|
|
2577
|
-
* The boundary is the one that retains FEWER old commits (tighter).
|
|
2578
|
-
*/
|
|
2579
|
-
calculateRetentionBoundary(commits: CommitInfo[]): number;
|
|
2580
|
-
/**
|
|
2581
|
-
* Perform the squash: create orphan with baseline + cherry-pick retained commits.
|
|
2582
|
-
* Uses the configured branch name instead of dynamic detection (Bug 1).
|
|
2583
|
-
*/
|
|
2584
|
-
private performSquash;
|
|
2585
|
-
/**
|
|
2586
|
-
* Best-effort cleanup after a failed squash. Aborts any half-finished
|
|
2587
|
-
* cherry-pick first, so a failure never leaves a sequencer behind (#249),
|
|
2588
|
-
* then returns to the configured branch and removes a leftover lock.
|
|
2589
|
-
*/
|
|
2590
|
-
private cleanupFailedSquash;
|
|
2591
|
-
/**
|
|
2592
|
-
* Force push to remote after squash (history rewrite requires force).
|
|
2593
|
-
*/
|
|
2594
|
-
private forcePushIfConfigured;
|
|
2595
|
-
}
|
|
2596
|
-
|
|
2597
|
-
export { CommitMessageGenerator, ContentHashCache, DEFAULT_SOURCE_NOTIFY_CONCURRENCY, DocumentProcessor, EnrichmentStore, EventQueue, FileSystemWatcher, GitignoreFilter, InitialScanTracker, IssuesManager, JeevesWatcher, ReindexTracker, SourceClient, SourceNotifyQueue, SourceNotifyQueueStoppedError, SourceReferenceError, SquashManager, SystemHealth, TemplateEngine, ValuesManager, VcsCoordinator, VcsManager, VectorStoreClient, VirtualRuleStore, applyRules, buildAttributes, buildTemplateEngine, compileRules, contentHash, createApiServer, createEmbeddingProvider, createHandlebarsInstance, createLogger, extractText, loadConfig, loadCustomHelpers, mergeEnrichment, parseSourceReference, parsedSourceReferenceSchema, pointId, registerBuiltinHelpers, resolveTemplateSource, resolvedSourceReferenceSchema, sourceAttributesSchema, sourceErrorCodeSchema, sourceNotifyQueueOptionsSchema, sourceRejectionCodeSchema, sourceRetrievalResultSchema, startFromConfig, watcherDescriptor, withoutSourceSupport };
|
|
2598
|
-
export type { AllHelpersIntrospection, ApiServerOptions, ApplyRulesOptions, ApplyRulesResult, CircuitBreakerSnapshot, CollectionInfo, CommitInfo, CompiledRule, CompiledTemplate, ConfigWarning, DocumentProcessorDeps, DocumentProcessorInterface, EmbedOptions, EmbeddingProvider, EnrichmentStoreInterface, EventQueueOptions, ExtractedText, Extractor, FileAttributes, FileSystemWatcherOptions, HelperModuleIntrospection, IndexOptions, InitialScanStatus, IssuesFile, JeevesWatcherFactories, JeevesWatcherRuntimeOptions, LoadConfigOptions, ParsedSourceReference, PausableQueue, PayloadFieldSchema, PendingReversion, ProcessFn, ProcessNowOptions, ProcessorConfig, ProviderFactory, PushError, ReindexStatus, RenderResult, ResolvedSourceReference, ResolvedWatchRoot, RuleAttributes, RuleLogger, ScrollPageResult, ScrolledPoint, SearchResult, SourceAttributes, SourceErrorCode, SourceNotifyQueueOptions, SourceOperationsInterface, SourceOperationsProvider, SourceProcess, SourceQueueIssues, SourceRejectionCode, SourceRenderOutcome, SourceRetrievalResult, SourceRetriever, SquashManagerOptions, SquashResult, SystemHealthOptions, ValuesIndex, VcsBreakerState, VectorPoint, VectorStore, WatchEvent, WatcherProcessor };
|
|
3108
|
+
export { ChangeSourceHealthTracker, CommitMessageGenerator, ContentHashCache, DEFAULT_SOURCE_NOTIFY_CONCURRENCY, DocumentLocks, DocumentProcessor, EnrichmentStore, EventQueue, FileSystemWatcher, GitignoreFilter, InitialScanTracker, Inventory, IssuesManager, JeevesWatcher, ReindexTracker, RootGitLock, SourceClient, SourceNotifyQueue, SourceNotifyQueueStoppedError, SourceReferenceError, SquashManager, SystemHealth, TemplateEngine, ValuesManager, VcsCoordinator, VcsManager, VectorStoreClient, VirtualRuleStore, applyRules, buildAttributes, buildTemplateEngine, compileRules, contentHash, createApiServer, createEmbeddingProvider, createHandlebarsInstance, createLogger, extractText, fileLockKey, loadConfig, loadCustomHelpers, mergeEnrichment, parseSourceReference, parsedSourceReferenceSchema, pointId, registerBuiltinHelpers, resolveTemplateSource, resolvedSourceReferenceSchema, sourceAttributesSchema, sourceErrorCodeSchema, sourceNotifyQueueOptionsSchema, sourceRejectionCodeSchema, sourceRetrievalResultSchema, startFromConfig, watcherDescriptor, withoutSourceSupport };
|
|
3109
|
+
export type { AllHelpersIntrospection, ApiServerOptions, ApplyRulesOptions, ApplyRulesResult, ChangeSink, CircuitBreakerSnapshot, ClassifiedEventType, CollectionInfo, CommitInfo, CompiledRule, CompiledTemplate, ConfigWarning, DocumentLockOptions, DocumentProcessorDeps, DocumentProcessorInterface, EmbedOptions, EmbeddingErrorSummary, EmbeddingHealthSnapshot, EmbeddingHealthState, EmbeddingProvider, EnrichmentStoreInterface, EventQueueOptions, ExtractedText, Extractor, FacetHit, FacetRead, FacetStore, FacetValue, FileAttributes, FileStats, FileSystemWatcherOptions, HelperModuleIntrospection, IndexCheckSkipReason, IndexCheckView, IndexOptions, InventoryEntry, IssuesFile, JeevesWatcherFactories, JeevesWatcherRuntimeOptions, LoadConfigOptions, ParcelImporter, ParcelWatcherModule, ParsedSourceReference, PausableQueue, PayloadFieldSchema, PendingReversion, ProcessFn, ProcessNowOptions, ProcessRestarter, ProcessRestarterDeps, ProcessingLimits, ProcessorConfig, ProviderFactory, PushError, RangeBound, RangeEnd, RawChangeEvent, RenderResult, ResolvedSourceReference, ResolvedWatchRoot, RestartRequest, RootUnavailableOptions, RuleAttributes, RuleLogger, ScrollPageResult, ScrolledPoint, SearchResult, SourceAttributes, SourceErrorCode, SourceNotifyQueueOptions, SourceOperationsInterface, SourceOperationsProvider, SourceProcess, SourceQueueIssues, SourceRejectionCode, SourceRenderOutcome, SourceRetrievalResult, SourceRetriever, SquashManagerOptions, SquashResult, SystemHealthOptions, SystemIndexState, ValuesIndex, VcsBreakerState, VcsFileChange, VcsManagerOptions, VectorPoint, VectorStore, WatchEvent, WatcherProcessor };
|