@karmaniverous/jeeves-watcher 0.17.7 → 0.17.9
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/cli/jeeves-watcher/{index-BRJ47BY6.js → index-07J6R3B8.js} +9 -10
- package/dist/cli/jeeves-watcher/index.js +8 -559
- package/dist/index.d.ts +5 -256
- package/dist/index.js +14 -565
- package/package.json +19 -26
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
2
|
import { createConfigQueryHandler as createConfigQueryHandler$1, createStatusHandler, createConfigApplyHandler, DEFAULT_PORTS, getBindAddress } from '@karmaniverous/jeeves';
|
|
3
|
-
import { n as normalizeSlashes, a as normalizeError, G as GitignoreFilter, e as executeReindex, V as VALID_REINDEX_SCOPES,
|
|
4
|
-
export {
|
|
3
|
+
import { n as normalizeSlashes, a as normalizeError, G as GitignoreFilter, e as executeReindex, V as VALID_REINDEX_SCOPES, m as mergeInferenceRules, i as isPathWatched, g as getWatchRootBases, C as CONFIG_WATCH_VALID_SCOPES, r as retry, s as sleep, l as loadConfig } from './index.js';
|
|
4
|
+
export { b as startFromConfig } from './index.js';
|
|
5
5
|
import { mkdirSync, existsSync, readFileSync, writeFileSync, rmSync, renameSync, readdirSync, statSync } from 'node:fs';
|
|
6
6
|
import { join, dirname, resolve, extname, basename, isAbsolute } from 'node:path';
|
|
7
7
|
import Database from 'better-sqlite3';
|
|
@@ -24,6 +24,7 @@ import { unified } from 'unified';
|
|
|
24
24
|
import yaml from 'js-yaml';
|
|
25
25
|
import chokidar from 'chokidar';
|
|
26
26
|
import Fastify from 'fastify';
|
|
27
|
+
import { inferenceRuleSchema, jeevesWatcherConfigSchema } from '@karmaniverous/jeeves-watcher-core';
|
|
27
28
|
import crypto from 'crypto';
|
|
28
29
|
import https from 'node:https';
|
|
29
30
|
import { createHash } from 'node:crypto';
|
|
@@ -816,7 +817,7 @@ function extractJsDocDescriptions(source) {
|
|
|
816
817
|
* @returns Introspection result with namespaced export names and descriptions.
|
|
817
818
|
*/
|
|
818
819
|
async function introspectHelperModule(filePath, namespace) {
|
|
819
|
-
const exports
|
|
820
|
+
const exports = {};
|
|
820
821
|
// Load module exports using shared utility (use parent dir as configDir, path as relative)
|
|
821
822
|
const namespaced = await loadNamespacedExports({ [namespace]: { path: filePath } }, '', (val) => typeof val === 'function');
|
|
822
823
|
// Try to read source for JSDoc extraction
|
|
@@ -835,9 +836,9 @@ async function introspectHelperModule(filePath, namespace) {
|
|
|
835
836
|
}
|
|
836
837
|
const nsExports = namespaced[namespace] ?? {};
|
|
837
838
|
for (const key of Object.keys(nsExports)) {
|
|
838
|
-
exports
|
|
839
|
+
exports[`${namespace}_${key}`] = jsDocMap[key] ?? '';
|
|
839
840
|
}
|
|
840
|
-
return { exports
|
|
841
|
+
return { exports };
|
|
841
842
|
}
|
|
842
843
|
/**
|
|
843
844
|
* Introspect all helper modules from config, returning exports for both mapHelpers and templateHelpers.
|
|
@@ -1294,9 +1295,7 @@ function renderEach(hbs, section, value) {
|
|
|
1294
1295
|
: undefined;
|
|
1295
1296
|
const parts = [];
|
|
1296
1297
|
for (const item of items) {
|
|
1297
|
-
const headingText = headingTpl
|
|
1298
|
-
? headingTpl(item)
|
|
1299
|
-
: '';
|
|
1298
|
+
const headingText = headingTpl ? headingTpl(item) : '';
|
|
1300
1299
|
if (headingText) {
|
|
1301
1300
|
parts.push(`${'#'.repeat(subHeadingLevel)} ${headingText}`);
|
|
1302
1301
|
}
|
|
@@ -1785,8 +1784,8 @@ function validateFacetTypes(schema, ruleName) {
|
|
|
1785
1784
|
async function loadCustomMapHelpers(helpers, configDir) {
|
|
1786
1785
|
const namespaced = await loadNamespacedExports(helpers, configDir, (val) => typeof val === 'function');
|
|
1787
1786
|
const merged = {};
|
|
1788
|
-
for (const [namespace, exports
|
|
1789
|
-
for (const [key, val] of Object.entries(exports
|
|
1787
|
+
for (const [namespace, exports] of Object.entries(namespaced)) {
|
|
1788
|
+
for (const [key, val] of Object.entries(exports)) {
|
|
1790
1789
|
merged[`${namespace}_${key}`] = val;
|
|
1791
1790
|
}
|
|
1792
1791
|
}
|
|
@@ -2,11 +2,11 @@
|
|
|
2
2
|
import { 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
6
|
import { packageDirectorySync } from 'package-directory';
|
|
6
7
|
import { readFileSync, existsSync, mkdirSync, renameSync, statSync, readdirSync } from 'node:fs';
|
|
7
8
|
import { cosmiconfig } from 'cosmiconfig';
|
|
8
|
-
import {
|
|
9
|
-
import { jsonMapMapSchema } from '@karmaniverous/jsonmap';
|
|
9
|
+
import { ZodError } from 'zod';
|
|
10
10
|
import { readdir, stat } from 'node:fs/promises';
|
|
11
11
|
import { parallel } from 'radash';
|
|
12
12
|
import ignore from 'ignore';
|
|
@@ -42,557 +42,6 @@ function mergeInferenceRules(existing, incoming) {
|
|
|
42
42
|
return merged;
|
|
43
43
|
}
|
|
44
44
|
|
|
45
|
-
/**
|
|
46
|
-
* @module config/defaults
|
|
47
|
-
* Default configuration values for jeeves-watcher. Pure data export, no I/O or side effects.
|
|
48
|
-
*/
|
|
49
|
-
/** Default root-level config values. */
|
|
50
|
-
const ROOT_DEFAULTS = {
|
|
51
|
-
stateDir: '.jeeves-metadata',
|
|
52
|
-
shutdownTimeoutMs: 10000,
|
|
53
|
-
};
|
|
54
|
-
/** Default configWatch values. */
|
|
55
|
-
const CONFIG_WATCH_DEFAULTS = {
|
|
56
|
-
enabled: true,
|
|
57
|
-
debounceMs: 1000,
|
|
58
|
-
};
|
|
59
|
-
/** Default API values. */
|
|
60
|
-
const API_DEFAULTS = {
|
|
61
|
-
host: '127.0.0.1',
|
|
62
|
-
port: DEFAULT_PORTS.watcher,
|
|
63
|
-
cacheTtlMs: 30000,
|
|
64
|
-
};
|
|
65
|
-
/** Default logging values. */
|
|
66
|
-
const LOGGING_DEFAULTS = {
|
|
67
|
-
level: 'info',
|
|
68
|
-
};
|
|
69
|
-
/** Default watch configuration. */
|
|
70
|
-
const WATCH_DEFAULTS = {
|
|
71
|
-
debounceMs: 300,
|
|
72
|
-
stabilityThresholdMs: 500,
|
|
73
|
-
usePolling: false,
|
|
74
|
-
pollIntervalMs: 1000,
|
|
75
|
-
respectGitignore: true,
|
|
76
|
-
};
|
|
77
|
-
/** Default embedding configuration. */
|
|
78
|
-
const EMBEDDING_DEFAULTS = {
|
|
79
|
-
chunkSize: 1000,
|
|
80
|
-
chunkOverlap: 200,
|
|
81
|
-
dimensions: 3072,
|
|
82
|
-
rateLimitPerMinute: 300,
|
|
83
|
-
concurrency: 5,
|
|
84
|
-
};
|
|
85
|
-
/** Default init command config template. */
|
|
86
|
-
const INIT_CONFIG_TEMPLATE = {
|
|
87
|
-
$schema: 'node_modules/@karmaniverous/jeeves-watcher/config.schema.json',
|
|
88
|
-
watch: {
|
|
89
|
-
paths: ['**/*.{md,markdown,txt,text,json,html,htm,pdf,docx}'],
|
|
90
|
-
ignored: ['**/node_modules/**', '**/.git/**', '**/.jeeves-watcher/**'],
|
|
91
|
-
},
|
|
92
|
-
configWatch: CONFIG_WATCH_DEFAULTS,
|
|
93
|
-
embedding: {
|
|
94
|
-
provider: 'gemini',
|
|
95
|
-
model: 'gemini-embedding-001',
|
|
96
|
-
dimensions: EMBEDDING_DEFAULTS.dimensions,
|
|
97
|
-
},
|
|
98
|
-
vectorStore: {
|
|
99
|
-
url: 'http://127.0.0.1:6333',
|
|
100
|
-
collectionName: 'jeeves-watcher',
|
|
101
|
-
},
|
|
102
|
-
stateDir: ROOT_DEFAULTS.stateDir,
|
|
103
|
-
api: API_DEFAULTS,
|
|
104
|
-
logging: LOGGING_DEFAULTS,
|
|
105
|
-
};
|
|
106
|
-
|
|
107
|
-
/**
|
|
108
|
-
* @module config/schemas/base
|
|
109
|
-
* Base configuration schemas: watch, logging, API.
|
|
110
|
-
*/
|
|
111
|
-
/**
|
|
112
|
-
* Watch configuration for file system monitoring.
|
|
113
|
-
*/
|
|
114
|
-
const watchConfigSchema = z.object({
|
|
115
|
-
/** Glob patterns to watch. */
|
|
116
|
-
paths: z
|
|
117
|
-
.array(z.string())
|
|
118
|
-
.min(1)
|
|
119
|
-
.describe('Glob patterns for files to watch (e.g., "**/*.md"). At least one required.'),
|
|
120
|
-
/** Glob patterns to ignore. */
|
|
121
|
-
ignored: z
|
|
122
|
-
.array(z.string())
|
|
123
|
-
.default(['**/node_modules/**'])
|
|
124
|
-
.describe('Glob patterns to exclude from watching (e.g., "**/node_modules/**").'),
|
|
125
|
-
/** Polling interval in milliseconds. */
|
|
126
|
-
pollIntervalMs: z
|
|
127
|
-
.number()
|
|
128
|
-
.optional()
|
|
129
|
-
.describe('Polling interval in milliseconds when usePolling is enabled.'),
|
|
130
|
-
/** Whether to use polling instead of native watchers. */
|
|
131
|
-
usePolling: z
|
|
132
|
-
.boolean()
|
|
133
|
-
.optional()
|
|
134
|
-
.describe('Use polling instead of native file system events (for network drives).'),
|
|
135
|
-
/** Debounce delay in milliseconds for file change events. */
|
|
136
|
-
debounceMs: z
|
|
137
|
-
.number()
|
|
138
|
-
.optional()
|
|
139
|
-
.describe('Debounce delay in milliseconds for file change events.'),
|
|
140
|
-
/** Time in milliseconds a file must be stable before processing. */
|
|
141
|
-
stabilityThresholdMs: z
|
|
142
|
-
.number()
|
|
143
|
-
.optional()
|
|
144
|
-
.describe('Time in milliseconds a file must remain unchanged before processing.'),
|
|
145
|
-
/** Whether to respect .gitignore files when processing. */
|
|
146
|
-
respectGitignore: z
|
|
147
|
-
.boolean()
|
|
148
|
-
.optional()
|
|
149
|
-
.describe('Skip files ignored by .gitignore in git repositories. Only applies to repos with a .git directory. Default: true.'),
|
|
150
|
-
/** Move detection configuration for correlating unlink+add as file moves. */
|
|
151
|
-
moveDetection: z
|
|
152
|
-
.object({
|
|
153
|
-
/** Enable move correlation. Default: true. */
|
|
154
|
-
enabled: z
|
|
155
|
-
.boolean()
|
|
156
|
-
.default(true)
|
|
157
|
-
.describe('Enable move detection via content hash correlation.'),
|
|
158
|
-
/** Buffer time in ms for holding unlink events before treating as deletes. Default: 2000. */
|
|
159
|
-
bufferMs: z
|
|
160
|
-
.number()
|
|
161
|
-
.int()
|
|
162
|
-
.min(100)
|
|
163
|
-
.default(2000)
|
|
164
|
-
.describe('How long (ms) to buffer unlink events before treating as deletes.'),
|
|
165
|
-
})
|
|
166
|
-
.optional()
|
|
167
|
-
.describe('Move detection: correlate unlink+add events as file moves to avoid re-embedding.'),
|
|
168
|
-
});
|
|
169
|
-
/**
|
|
170
|
-
* Configuration watch settings.
|
|
171
|
-
*/
|
|
172
|
-
const configWatchConfigSchema = z.object({
|
|
173
|
-
/** Whether config file watching is enabled. */
|
|
174
|
-
enabled: z
|
|
175
|
-
.boolean()
|
|
176
|
-
.optional()
|
|
177
|
-
.describe('Enable automatic reloading when config file changes.'),
|
|
178
|
-
/** Debounce delay in milliseconds for config change events. */
|
|
179
|
-
debounceMs: z
|
|
180
|
-
.number()
|
|
181
|
-
.optional()
|
|
182
|
-
.describe('Debounce delay in milliseconds for config file change detection.'),
|
|
183
|
-
/** Reindex scope triggered on config change. */
|
|
184
|
-
reindex: z
|
|
185
|
-
.union([
|
|
186
|
-
z
|
|
187
|
-
.literal('issues')
|
|
188
|
-
.describe('Re-process only files with recorded issues.'),
|
|
189
|
-
z.literal('full').describe('Full reindex of all watched files.'),
|
|
190
|
-
z
|
|
191
|
-
.literal('rules')
|
|
192
|
-
.describe('Re-apply inference rules to existing points without re-embedding.'),
|
|
193
|
-
])
|
|
194
|
-
.optional()
|
|
195
|
-
.describe('Reindex scope triggered on config change. Default: issues.'),
|
|
196
|
-
});
|
|
197
|
-
/**
|
|
198
|
-
* API server configuration.
|
|
199
|
-
*/
|
|
200
|
-
const apiConfigSchema = z.object({
|
|
201
|
-
/** Host to bind to. */
|
|
202
|
-
host: z
|
|
203
|
-
.string()
|
|
204
|
-
.optional()
|
|
205
|
-
.describe('Host address for API server (e.g., "127.0.0.1", "0.0.0.0").'),
|
|
206
|
-
/** Port to listen on. */
|
|
207
|
-
port: z.number().optional().describe('Port for API server (e.g., 1936).'),
|
|
208
|
-
/** Read endpoint cache TTL in milliseconds. */
|
|
209
|
-
cacheTtlMs: z
|
|
210
|
-
.number()
|
|
211
|
-
.optional()
|
|
212
|
-
.describe('TTL in milliseconds for caching read-heavy endpoints (e.g., /status, /config). Default: 30000.'),
|
|
213
|
-
});
|
|
214
|
-
/**
|
|
215
|
-
* Logging configuration.
|
|
216
|
-
*/
|
|
217
|
-
const loggingConfigSchema = z.object({
|
|
218
|
-
/** Log level. */
|
|
219
|
-
level: z
|
|
220
|
-
.string()
|
|
221
|
-
.optional()
|
|
222
|
-
.describe('Logging level (trace, debug, info, warn, error, fatal).'),
|
|
223
|
-
/** Log file path. */
|
|
224
|
-
file: z
|
|
225
|
-
.string()
|
|
226
|
-
.optional()
|
|
227
|
-
.describe('Path to log file (logs to stdout if omitted).'),
|
|
228
|
-
});
|
|
229
|
-
|
|
230
|
-
/**
|
|
231
|
-
* @module config/schemas/inference
|
|
232
|
-
* Inference rule and schema configuration schemas.
|
|
233
|
-
*/
|
|
234
|
-
/**
|
|
235
|
-
* A JSON Schema property definition with optional custom keywords.
|
|
236
|
-
* Supports standard JSON Schema keywords plus custom `set` and `uiHint`.
|
|
237
|
-
*/
|
|
238
|
-
const propertySchemaSchema = z.record(z.string(), z.unknown());
|
|
239
|
-
/**
|
|
240
|
-
* A schema object: properties with JSON Schema definitions.
|
|
241
|
-
*/
|
|
242
|
-
const schemaObjectSchema = z.object({
|
|
243
|
-
type: z
|
|
244
|
-
.literal('object')
|
|
245
|
-
.optional()
|
|
246
|
-
.describe('JSON Schema type (always "object" for schema definitions).'),
|
|
247
|
-
properties: z
|
|
248
|
-
.record(z.string(), propertySchemaSchema)
|
|
249
|
-
.optional()
|
|
250
|
-
.describe('Map of property names to JSON Schema property definitions.'),
|
|
251
|
-
});
|
|
252
|
-
/**
|
|
253
|
-
* Global schema entry: inline object or file path.
|
|
254
|
-
*/
|
|
255
|
-
const schemaEntrySchema = z.union([
|
|
256
|
-
schemaObjectSchema,
|
|
257
|
-
z.string().describe('File path to a JSON schema file.'),
|
|
258
|
-
]);
|
|
259
|
-
/**
|
|
260
|
-
* Schema reference: either a named schema reference (string) or an inline schema object.
|
|
261
|
-
*/
|
|
262
|
-
const schemaReferenceSchema = z.union([
|
|
263
|
-
z.string().describe('Named reference to a global schema.'),
|
|
264
|
-
schemaObjectSchema,
|
|
265
|
-
]);
|
|
266
|
-
/** Render body section. */
|
|
267
|
-
const renderBodySectionSchema = z.object({
|
|
268
|
-
/** Key path in the template context to render. */
|
|
269
|
-
path: z.string().min(1).describe('Key path in template context to render.'),
|
|
270
|
-
/** Markdown heading level for this section (1-6). */
|
|
271
|
-
heading: z.number().min(1).max(6).describe('Markdown heading level (1-6).'),
|
|
272
|
-
/** Override heading text (default: titlecased path). */
|
|
273
|
-
label: z.string().optional().describe('Override heading text.'),
|
|
274
|
-
/** Name of a registered Handlebars helper used as a format handler. */
|
|
275
|
-
format: z
|
|
276
|
-
.string()
|
|
277
|
-
.optional()
|
|
278
|
-
.describe('Name of a registered Handlebars helper used as a format handler.'),
|
|
279
|
-
/** Additional args passed to the format helper. */
|
|
280
|
-
formatArgs: z
|
|
281
|
-
.array(z.unknown())
|
|
282
|
-
.optional()
|
|
283
|
-
.describe('Additional args passed to the format helper.'),
|
|
284
|
-
/** If true, the value at path is treated as an array and iterated. */
|
|
285
|
-
each: z
|
|
286
|
-
.boolean()
|
|
287
|
-
.optional()
|
|
288
|
-
.describe('If true, the value at path is treated as an array and iterated.'),
|
|
289
|
-
/** Handlebars template string for per-item heading text (used when each=true). */
|
|
290
|
-
headingTemplate: z
|
|
291
|
-
.string()
|
|
292
|
-
.optional()
|
|
293
|
-
.describe('Handlebars template string for per-item heading text (used when each=true).'),
|
|
294
|
-
/** Key path within each item to use as renderable content (used when each=true). */
|
|
295
|
-
contentPath: z
|
|
296
|
-
.string()
|
|
297
|
-
.optional()
|
|
298
|
-
.describe('Key path within each item to use as renderable content (used when each=true).'),
|
|
299
|
-
/** Key path within each item to sort by (used when each=true). */
|
|
300
|
-
sort: z
|
|
301
|
-
.string()
|
|
302
|
-
.optional()
|
|
303
|
-
.describe('Key path within each item to sort by (used when each=true).'),
|
|
304
|
-
});
|
|
305
|
-
/** Render config: YAML frontmatter + ordered body sections. */
|
|
306
|
-
const renderConfigSchema = z.object({
|
|
307
|
-
/** Keys or glob patterns to extract from context and include as YAML frontmatter. */
|
|
308
|
-
frontmatter: z
|
|
309
|
-
.array(z.string().min(1))
|
|
310
|
-
.describe('Keys or glob patterns to include as YAML frontmatter. ' +
|
|
311
|
-
'Supports picomatch globs (e.g. "*") and "!"-prefixed exclusion patterns (e.g. "!_*"). ' +
|
|
312
|
-
'Explicit names preserve declaration order; glob-matched keys are sorted alphabetically.'),
|
|
313
|
-
/** Ordered markdown body sections. */
|
|
314
|
-
body: z
|
|
315
|
-
.array(renderBodySectionSchema)
|
|
316
|
-
.describe('Ordered markdown body sections.'),
|
|
317
|
-
});
|
|
318
|
-
/**
|
|
319
|
-
* An inference rule that enriches document metadata.
|
|
320
|
-
*/
|
|
321
|
-
const inferenceRuleSchema = z
|
|
322
|
-
.object({
|
|
323
|
-
/** Unique name for this inference rule. */
|
|
324
|
-
name: z
|
|
325
|
-
.string()
|
|
326
|
-
.min(1)
|
|
327
|
-
.describe('Unique name identifying this inference rule.'),
|
|
328
|
-
/** Human-readable description of what this rule does. */
|
|
329
|
-
description: z
|
|
330
|
-
.string()
|
|
331
|
-
.min(1)
|
|
332
|
-
.describe('Human-readable description of what this rule does.'),
|
|
333
|
-
/** JSON Schema object to match against document metadata. */
|
|
334
|
-
match: z
|
|
335
|
-
.record(z.string(), z.unknown())
|
|
336
|
-
.describe('JSON Schema object to match against file attributes.'),
|
|
337
|
-
/** Array of schema references to merge (named refs and/or inline objects). */
|
|
338
|
-
schema: z
|
|
339
|
-
.array(schemaReferenceSchema)
|
|
340
|
-
.optional()
|
|
341
|
-
.describe('Array of schema references (named schema refs or inline objects) merged left-to-right.'),
|
|
342
|
-
/** JsonMap transformation (inline or reference to named map). */
|
|
343
|
-
map: z
|
|
344
|
-
.union([jsonMapMapSchema, z.string()])
|
|
345
|
-
.optional()
|
|
346
|
-
.describe('JsonMap transformation (inline definition, named map reference, or .json file path).'),
|
|
347
|
-
/** Handlebars template (inline string, named ref, or .hbs/.handlebars file path). */
|
|
348
|
-
template: z
|
|
349
|
-
.string()
|
|
350
|
-
.optional()
|
|
351
|
-
.describe('Handlebars content template (inline string, named ref, or .hbs/.handlebars file path).'),
|
|
352
|
-
/** Declarative structured renderer configuration (mutually exclusive with template). */
|
|
353
|
-
render: renderConfigSchema
|
|
354
|
-
.optional()
|
|
355
|
-
.describe('Declarative render configuration for frontmatter + structured Markdown output (mutually exclusive with template).'),
|
|
356
|
-
/** Output file extension override (e.g. "md", "html", "txt"). Requires template or render. */
|
|
357
|
-
renderAs: z
|
|
358
|
-
.string()
|
|
359
|
-
.regex(/^[a-z0-9]{1,10}$/, 'renderAs must be 1-10 lowercase alphanumeric characters')
|
|
360
|
-
.optional()
|
|
361
|
-
.describe('Output file extension override (without dot). Requires template or render.'),
|
|
362
|
-
})
|
|
363
|
-
.superRefine((val, ctx) => {
|
|
364
|
-
if (val.render && val.template) {
|
|
365
|
-
ctx.addIssue({
|
|
366
|
-
code: 'custom',
|
|
367
|
-
path: ['render'],
|
|
368
|
-
message: 'render is mutually exclusive with template',
|
|
369
|
-
});
|
|
370
|
-
}
|
|
371
|
-
if (val.renderAs && !val.template && !val.render) {
|
|
372
|
-
ctx.addIssue({
|
|
373
|
-
code: 'custom',
|
|
374
|
-
path: ['renderAs'],
|
|
375
|
-
message: 'renderAs requires template or render',
|
|
376
|
-
});
|
|
377
|
-
}
|
|
378
|
-
});
|
|
379
|
-
|
|
380
|
-
/**
|
|
381
|
-
* @module config/schemas/services
|
|
382
|
-
* Service configuration schemas: embedding and vector store.
|
|
383
|
-
*/
|
|
384
|
-
/**
|
|
385
|
-
* Embedding model configuration.
|
|
386
|
-
*/
|
|
387
|
-
const embeddingConfigSchema = z.object({
|
|
388
|
-
/** The embedding model provider. */
|
|
389
|
-
provider: z
|
|
390
|
-
.string()
|
|
391
|
-
.default('gemini')
|
|
392
|
-
.describe('Embedding provider name (e.g., "gemini", "openai").'),
|
|
393
|
-
/** The embedding model name. */
|
|
394
|
-
model: z
|
|
395
|
-
.string()
|
|
396
|
-
.default('gemini-embedding-001')
|
|
397
|
-
.describe('Embedding model identifier (e.g., "gemini-embedding-001", "text-embedding-3-small").'),
|
|
398
|
-
/** Maximum tokens per chunk for splitting. */
|
|
399
|
-
chunkSize: z
|
|
400
|
-
.number()
|
|
401
|
-
.optional()
|
|
402
|
-
.describe('Maximum chunk size in characters for text splitting.'),
|
|
403
|
-
/** Overlap between chunks in tokens. */
|
|
404
|
-
chunkOverlap: z
|
|
405
|
-
.number()
|
|
406
|
-
.optional()
|
|
407
|
-
.describe('Character overlap between consecutive chunks.'),
|
|
408
|
-
/** Embedding vector dimensions. */
|
|
409
|
-
dimensions: z
|
|
410
|
-
.number()
|
|
411
|
-
.optional()
|
|
412
|
-
.describe('Embedding vector dimensions (must match model output).'),
|
|
413
|
-
/** API key for the embedding provider. */
|
|
414
|
-
apiKey: z
|
|
415
|
-
.string()
|
|
416
|
-
.optional()
|
|
417
|
-
.describe('API key for embedding provider (supports ${ENV_VAR} substitution).'),
|
|
418
|
-
/** Maximum embedding requests per minute. */
|
|
419
|
-
rateLimitPerMinute: z
|
|
420
|
-
.number()
|
|
421
|
-
.optional()
|
|
422
|
-
.describe('Maximum embedding API requests per minute (rate limiting).'),
|
|
423
|
-
/** Maximum concurrent embedding requests. */
|
|
424
|
-
concurrency: z
|
|
425
|
-
.number()
|
|
426
|
-
.optional()
|
|
427
|
-
.describe('Maximum concurrent embedding requests.'),
|
|
428
|
-
});
|
|
429
|
-
/**
|
|
430
|
-
* Vector store configuration for Qdrant.
|
|
431
|
-
*/
|
|
432
|
-
const vectorStoreConfigSchema = z.object({
|
|
433
|
-
/** Qdrant server URL. */
|
|
434
|
-
url: z
|
|
435
|
-
.string()
|
|
436
|
-
.describe('Qdrant server URL (e.g., "http://localhost:6333").'),
|
|
437
|
-
/** Qdrant collection name. */
|
|
438
|
-
collectionName: z
|
|
439
|
-
.string()
|
|
440
|
-
.describe('Qdrant collection name for vector storage.'),
|
|
441
|
-
/** Qdrant API key. */
|
|
442
|
-
apiKey: z
|
|
443
|
-
.string()
|
|
444
|
-
.optional()
|
|
445
|
-
.describe('Qdrant API key for authentication (supports ${ENV_VAR} substitution).'),
|
|
446
|
-
});
|
|
447
|
-
|
|
448
|
-
/**
|
|
449
|
-
* @module config/schemas/root
|
|
450
|
-
* Root configuration schema combining all sub-schemas.
|
|
451
|
-
*/
|
|
452
|
-
/**
|
|
453
|
-
* Top-level configuration for jeeves-watcher.
|
|
454
|
-
*/
|
|
455
|
-
const jeevesWatcherConfigSchema = z.object({
|
|
456
|
-
/** Optional description of this watcher deployment's organizational strategy. */
|
|
457
|
-
description: z
|
|
458
|
-
.string()
|
|
459
|
-
.optional()
|
|
460
|
-
.describe("Human-readable description of this deployment's organizational strategy and content domains."),
|
|
461
|
-
/** Global named schema collection. */
|
|
462
|
-
schemas: z
|
|
463
|
-
.record(z.string(), schemaEntrySchema)
|
|
464
|
-
.optional()
|
|
465
|
-
.describe('Global named schema definitions (inline objects or file paths) referenced by inference rules.'),
|
|
466
|
-
/** File system watch configuration. */
|
|
467
|
-
watch: watchConfigSchema.describe('File system watch configuration.'),
|
|
468
|
-
/** Configuration file watch settings. */
|
|
469
|
-
configWatch: configWatchConfigSchema
|
|
470
|
-
.optional()
|
|
471
|
-
.describe('Configuration file watch settings.'),
|
|
472
|
-
/** Embedding model configuration. */
|
|
473
|
-
embedding: embeddingConfigSchema.describe('Embedding model configuration.'),
|
|
474
|
-
/** Vector store configuration. */
|
|
475
|
-
vectorStore: vectorStoreConfigSchema.describe('Qdrant vector store configuration.'),
|
|
476
|
-
/** API server configuration. */
|
|
477
|
-
api: apiConfigSchema.optional().describe('API server configuration.'),
|
|
478
|
-
/** Directory for persistent state files (issues.json, values.json, enrichments.sqlite). */
|
|
479
|
-
stateDir: z
|
|
480
|
-
.string()
|
|
481
|
-
.optional()
|
|
482
|
-
.describe('Directory for persistent state files (issues.json, values.json, enrichments.sqlite). Defaults to .jeeves-metadata.'),
|
|
483
|
-
/** Rules for inferring metadata from document properties (inline objects or file paths). */
|
|
484
|
-
inferenceRules: z
|
|
485
|
-
.array(z.union([inferenceRuleSchema, z.string()]))
|
|
486
|
-
.optional()
|
|
487
|
-
.describe('Rules for inferring metadata from file attributes. Each entry may be an inline rule object or a file path to a JSON rule file (resolved relative to config directory).'),
|
|
488
|
-
/** Reusable named JsonMap transformations (inline objects or .json file paths). */
|
|
489
|
-
maps: z
|
|
490
|
-
.record(z.string(), z.union([
|
|
491
|
-
jsonMapMapSchema,
|
|
492
|
-
z.string(),
|
|
493
|
-
z.object({
|
|
494
|
-
/** The JsonMap definition (inline object or file path). */
|
|
495
|
-
map: jsonMapMapSchema.or(z.string()),
|
|
496
|
-
/** Optional human-readable description of this map. */
|
|
497
|
-
description: z.string().optional(),
|
|
498
|
-
}),
|
|
499
|
-
]))
|
|
500
|
-
.optional()
|
|
501
|
-
.describe('Reusable named JsonMap transformations (inline definition or .json file path resolved relative to config directory).'),
|
|
502
|
-
/** Reusable named Handlebars templates (inline strings or .hbs/.handlebars file paths). */
|
|
503
|
-
templates: z
|
|
504
|
-
.record(z.string(), z.union([
|
|
505
|
-
z.string(),
|
|
506
|
-
z.object({
|
|
507
|
-
/** The Handlebars template source (inline string or file path). */
|
|
508
|
-
template: z.string(),
|
|
509
|
-
/** Optional human-readable description of this template. */
|
|
510
|
-
description: z.string().optional(),
|
|
511
|
-
}),
|
|
512
|
-
]))
|
|
513
|
-
.optional()
|
|
514
|
-
.describe('Named reusable Handlebars templates (inline strings or .hbs/.handlebars file paths).'),
|
|
515
|
-
/** Custom Handlebars helper registration. */
|
|
516
|
-
templateHelpers: z
|
|
517
|
-
.record(z.string(), z.object({
|
|
518
|
-
/** File path to the helper module (resolved relative to config directory). */
|
|
519
|
-
path: z.string(),
|
|
520
|
-
/** Optional human-readable description of this helper. */
|
|
521
|
-
description: z.string().optional(),
|
|
522
|
-
}))
|
|
523
|
-
.optional()
|
|
524
|
-
.describe('Custom Handlebars helper registration.'),
|
|
525
|
-
/** Custom JsonMap lib function registration. */
|
|
526
|
-
mapHelpers: z
|
|
527
|
-
.record(z.string(), z.object({
|
|
528
|
-
/** File path to the helper module (resolved relative to config directory). */
|
|
529
|
-
path: z.string(),
|
|
530
|
-
/** Optional human-readable description of this helper. */
|
|
531
|
-
description: z.string().optional(),
|
|
532
|
-
}))
|
|
533
|
-
.optional()
|
|
534
|
-
.describe('Custom JsonMap lib function registration.'),
|
|
535
|
-
/** Reindex configuration. */
|
|
536
|
-
reindex: z
|
|
537
|
-
.object({
|
|
538
|
-
/** URL to call when reindex completes. */
|
|
539
|
-
callbackUrl: z.url().optional(),
|
|
540
|
-
/** Maximum concurrent file operations during reindex. */
|
|
541
|
-
concurrency: z
|
|
542
|
-
.number()
|
|
543
|
-
.int()
|
|
544
|
-
.min(1)
|
|
545
|
-
.default(50)
|
|
546
|
-
.describe('Maximum concurrent file operations during reindex (default 50).'),
|
|
547
|
-
})
|
|
548
|
-
.optional()
|
|
549
|
-
.describe('Reindex configuration.'),
|
|
550
|
-
/** Named Qdrant filter patterns for skill-activated behaviors. */
|
|
551
|
-
/** Search configuration including score thresholds and hybrid search. */
|
|
552
|
-
search: z
|
|
553
|
-
.object({
|
|
554
|
-
/** Score thresholds for categorizing search result quality. */
|
|
555
|
-
scoreThresholds: z
|
|
556
|
-
.object({
|
|
557
|
-
/** Minimum score for a result to be considered a strong match. */
|
|
558
|
-
strong: z.number().min(-1).max(1),
|
|
559
|
-
/** Minimum score for a result to be considered relevant. */
|
|
560
|
-
relevant: z.number().min(-1).max(1),
|
|
561
|
-
/** Maximum score below which results are considered noise. */
|
|
562
|
-
noise: z.number().min(-1).max(1),
|
|
563
|
-
})
|
|
564
|
-
.optional(),
|
|
565
|
-
/** Hybrid search configuration combining vector and full-text search. */
|
|
566
|
-
hybrid: z
|
|
567
|
-
.object({
|
|
568
|
-
/** Enable hybrid search with RRF fusion. Default: false. */
|
|
569
|
-
enabled: z.boolean().default(false),
|
|
570
|
-
/** Weight for text (BM25) results in RRF fusion. Default: 0.3. */
|
|
571
|
-
textWeight: z.number().min(0).max(1).default(0.3),
|
|
572
|
-
})
|
|
573
|
-
.optional(),
|
|
574
|
-
})
|
|
575
|
-
.optional()
|
|
576
|
-
.describe('Search configuration including score thresholds and hybrid search.'),
|
|
577
|
-
/** Logging configuration. */
|
|
578
|
-
logging: loggingConfigSchema.optional().describe('Logging configuration.'),
|
|
579
|
-
/** Timeout in milliseconds for graceful shutdown. */
|
|
580
|
-
shutdownTimeoutMs: z
|
|
581
|
-
.number()
|
|
582
|
-
.optional()
|
|
583
|
-
.describe('Timeout in milliseconds for graceful shutdown.'),
|
|
584
|
-
/** Maximum consecutive system-level failures before triggering fatal error. Default: Infinity. */
|
|
585
|
-
maxRetries: z
|
|
586
|
-
.number()
|
|
587
|
-
.optional()
|
|
588
|
-
.describe('Maximum consecutive system-level failures before triggering fatal error. Default: Infinity.'),
|
|
589
|
-
/** Maximum backoff delay in milliseconds for system errors. Default: 60000. */
|
|
590
|
-
maxBackoffMs: z
|
|
591
|
-
.number()
|
|
592
|
-
.optional()
|
|
593
|
-
.describe('Maximum backoff delay in milliseconds for system errors. Default: 60000.'),
|
|
594
|
-
});
|
|
595
|
-
|
|
596
45
|
/**
|
|
597
46
|
* @module config/substituteEnvVars
|
|
598
47
|
*
|
|
@@ -818,7 +267,7 @@ async function startFromConfig(configPath, descriptor) {
|
|
|
818
267
|
const config = await loadConfig(resolvedPath);
|
|
819
268
|
// Dynamic import breaks the circular dependency between this module
|
|
820
269
|
// and app/index.ts (which defines JeevesWatcher and re-exports startFromConfig).
|
|
821
|
-
const { JeevesWatcher } = await import('./index-
|
|
270
|
+
const { JeevesWatcher } = await import('./index-07J6R3B8.js');
|
|
822
271
|
const app = new JeevesWatcher(config, resolvedPath, descriptor);
|
|
823
272
|
installShutdownHandlers(() => app.stop());
|
|
824
273
|
await app.start();
|
|
@@ -1996,11 +1445,11 @@ const version = getPackageVersion(import.meta.url);
|
|
|
1996
1445
|
*/
|
|
1997
1446
|
const watcherDescriptor = {
|
|
1998
1447
|
// Identity
|
|
1999
|
-
name:
|
|
1448
|
+
name: COMPONENT_NAME,
|
|
2000
1449
|
version,
|
|
2001
|
-
servicePackage:
|
|
2002
|
-
pluginPackage:
|
|
2003
|
-
defaultPort:
|
|
1450
|
+
servicePackage: SERVICE_PACKAGE,
|
|
1451
|
+
pluginPackage: PLUGIN_PACKAGE,
|
|
1452
|
+
defaultPort: DEFAULT_PORT$1,
|
|
2004
1453
|
// Config
|
|
2005
1454
|
configSchema: jeevesWatcherConfigSchema,
|
|
2006
1455
|
configFileName: 'config.json',
|
|
@@ -2049,4 +1498,4 @@ const watcherDescriptor = {
|
|
|
2049
1498
|
const program = createServiceCli(watcherDescriptor);
|
|
2050
1499
|
program.parse();
|
|
2051
1500
|
|
|
2052
|
-
export { CONFIG_WATCH_VALID_SCOPES as C, GitignoreFilter as G, VALID_REINDEX_SCOPES as V, normalizeError as a,
|
|
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 };
|