@karmaniverous/jeeves-meta 0.11.3 → 0.12.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.d.ts CHANGED
@@ -1,4 +1,6 @@
1
1
  import { z } from 'zod';
2
+ import { Command } from 'commander';
3
+ import { JeevesComponentDescriptor } from '@karmaniverous/jeeves';
2
4
  import pino, { Logger } from 'pino';
3
5
  import * as fastify from 'fastify';
4
6
  import { FastifyInstance, FastifyBaseLogger } from 'fastify';
@@ -32,6 +34,160 @@ declare function listArchiveFiles(metaPath: string): string[];
32
34
  */
33
35
  declare function pruneArchive(metaPath: string, maxArchive: number): Promise<number>;
34
36
 
37
+ /**
38
+ * Per-cycle context package computed by the orchestrator.
39
+ *
40
+ * Shared inputs that multiple subprocesses need are computed once
41
+ * and serialized into each subprocess's task prompt.
42
+ *
43
+ * @module interfaces/MetaContext
44
+ */
45
+ /**
46
+ * Context package for a single synthesis cycle.
47
+ *
48
+ * The orchestrator computes this once per cycle from the meta path,
49
+ * ownership tree, watcher walk results, and filesystem reads.
50
+ */
51
+ interface MetaContext {
52
+ /** Absolute path to the .meta directory. */
53
+ path: string;
54
+ /** All files in scope (absolute paths). */
55
+ scopeFiles: string[];
56
+ /** Files changed since _generatedAt (absolute paths). */
57
+ deltaFiles: string[];
58
+ /** Child _content outputs, keyed by relative path. */
59
+ childMetas: Record<string, unknown>;
60
+ /** Cross-referenced meta _content outputs, keyed by owner path. */
61
+ crossRefMetas: Record<string, unknown>;
62
+ /** _content from the last cycle, or null on first run. */
63
+ previousContent: string | null;
64
+ /** _feedback from the last cycle, or null on first run. */
65
+ previousFeedback: string | null;
66
+ /** Current _steer value, or null if unset. */
67
+ steer: string | null;
68
+ /** _state from the last cycle, or null on first run. */
69
+ previousState: unknown;
70
+ /** Archive snapshot file paths (for steer change detection, etc.). */
71
+ archives: string[];
72
+ }
73
+
74
+ /**
75
+ * Pluggable executor interface for LLM subprocess invocation.
76
+ *
77
+ * @module interfaces/MetaExecutor
78
+ */
79
+ /** Options for spawning a synthesis subprocess. */
80
+ interface MetaSpawnOptions {
81
+ /** Model override for this subprocess. */
82
+ model?: string;
83
+ /** Timeout in seconds. */
84
+ timeout?: number;
85
+ /** Label for the spawned session. */
86
+ label?: string;
87
+ /** Thinking level (e.g. "low", "medium", "high"). */
88
+ thinking?: string;
89
+ }
90
+ /** Result of a spawn call, including optional token usage. */
91
+ interface MetaSpawnResult {
92
+ /** Subprocess output text. */
93
+ output: string;
94
+ /** Token count for this call, if available from the executor. */
95
+ tokens?: number;
96
+ }
97
+ /**
98
+ * Interface for spawning synthesis subprocesses.
99
+ *
100
+ * The executor abstracts the LLM invocation mechanism. The orchestrator
101
+ * calls spawn() sequentially for architect, builder, and critic steps.
102
+ * Each call blocks until the subprocess completes and returns its result.
103
+ */
104
+ interface MetaExecutor {
105
+ /**
106
+ * Spawn a subprocess with the given task prompt.
107
+ *
108
+ * @param task - Full task prompt for the subprocess.
109
+ * @param options - Optional model and timeout overrides.
110
+ * @returns The subprocess result with output and optional token count.
111
+ */
112
+ spawn(task: string, options?: MetaSpawnOptions): Promise<MetaSpawnResult>;
113
+ }
114
+
115
+ /**
116
+ * Abstraction over the jeeves-watcher HTTP API.
117
+ *
118
+ * The service uses this for filesystem enumeration (POST /walk),
119
+ * virtual rule registration (POST /rules/register), and archive reads
120
+ * via filter-only point scans (POST /scan).
121
+ *
122
+ * @module interfaces/WatcherClient
123
+ */
124
+ /** An inference rule to register with the watcher. */
125
+ interface InferenceRuleSpec {
126
+ /** Rule name. */
127
+ name: string;
128
+ /** Rule description. */
129
+ description: string;
130
+ /** JSON Schema match criteria. */
131
+ match: Record<string, unknown>;
132
+ /** Schema array with set keywords. */
133
+ schema: unknown[];
134
+ /** Declarative render config. */
135
+ render?: Record<string, unknown>;
136
+ /** Handlebars template name. */
137
+ template?: string;
138
+ /** Render output format. */
139
+ renderAs?: string;
140
+ }
141
+ /** Request shape for watcher scan queries. */
142
+ interface WatcherScanRequest {
143
+ filter: Record<string, unknown>;
144
+ limit?: number;
145
+ cursor?: string;
146
+ fields?: string[];
147
+ countOnly?: boolean;
148
+ }
149
+ /** A single point returned from watcher scan. */
150
+ interface WatcherScanPoint {
151
+ id?: string | number;
152
+ payload?: Record<string, unknown>;
153
+ }
154
+ /** Response shape for watcher scan queries. */
155
+ interface WatcherScanResult {
156
+ points: WatcherScanPoint[];
157
+ cursor: string | null;
158
+ }
159
+ /**
160
+ * Interface for watcher HTTP operations.
161
+ *
162
+ * Implementations handle retry with backoff internally.
163
+ */
164
+ interface WatcherClient {
165
+ /**
166
+ * Register virtual inference rules with the watcher.
167
+ *
168
+ * @param source - Source identifier (e.g. 'jeeves-meta').
169
+ * @param rules - Array of inference rules to register.
170
+ */
171
+ registerRules(source: string, rules: InferenceRuleSpec[]): Promise<void>;
172
+ /**
173
+ * Walk filesystem using glob patterns.
174
+ *
175
+ * @param globs - Array of glob patterns to match against.
176
+ * @returns Promise resolving to array of matching file paths.
177
+ */
178
+ walk(globs: string[]): Promise<string[]>;
179
+ /**
180
+ * Run a filter-only point scan against the watcher index.
181
+ *
182
+ * Optional so narrow test doubles do not need to implement archive-read
183
+ * support unless a test exercises that path.
184
+ *
185
+ * @param request - Scan filter, pagination, and projection options.
186
+ * @returns Matching points and the next cursor.
187
+ */
188
+ scan?(request: WatcherScanRequest): Promise<WatcherScanResult>;
189
+ }
190
+
35
191
  /**
36
192
  * Zod schema for jeeves-meta service configuration.
37
193
  *
@@ -210,156 +366,329 @@ declare const SERVICE_NAME = "jeeves-meta";
210
366
  declare const SERVICE_VERSION: string;
211
367
 
212
368
  /**
213
- * Load and resolve jeeves-meta service config.
369
+ * Custom CLI commands for the jeeves-meta service.
214
370
  *
215
- * Supports \@file: indirection and environment-variable substitution (dollar-brace pattern).
371
+ * Registered via `descriptor.customCliCommands` and added to the
372
+ * standard service CLI produced by `createServiceCli`.
216
373
  *
217
- * @module configLoader
374
+ * @module customCliCommands
218
375
  */
219
376
 
377
+ /** Register all custom meta commands on the parent program. */
378
+ declare function registerCustomCliCommands(program: Command): void;
379
+
220
380
  /**
221
- * Resolve config path from --config flag or JEEVES_META_CONFIG env var.
381
+ * Single-threaded synthesis queue with priority support and deduplication.
222
382
  *
223
- * @param args - CLI arguments (process.argv.slice(2)).
224
- * @returns Resolved config path.
225
- * @throws If no config path found.
383
+ * The scheduler enqueues the stalest candidate each tick. HTTP-triggered
384
+ * synthesis requests get priority (inserted at front). A path appears at
385
+ * most once in the queue; re-triggering returns the current position.
386
+ *
387
+ * @module queue
226
388
  */
227
- declare function resolveConfigPath(args: string[]): string;
389
+
390
+ /** A queued synthesis work item. */
391
+ interface QueueItem {
392
+ path: string;
393
+ priority: boolean;
394
+ enqueuedAt: string;
395
+ }
396
+ /** Result returned by {@link SynthesisQueue.enqueue}. */
397
+ interface EnqueueResult {
398
+ position: number;
399
+ alreadyQueued: boolean;
400
+ }
401
+ /** Snapshot of queue state for the /status endpoint. */
402
+ interface QueueState {
403
+ depth: number;
404
+ items: Array<{
405
+ path: string;
406
+ priority: boolean;
407
+ enqueuedAt: string;
408
+ }>;
409
+ }
228
410
  /**
229
- * Load service config from a JSON file.
230
- *
231
- * Resolves \@file: references for defaultArchitect and defaultCritic,
232
- * and substitutes environment-variable placeholders throughout.
411
+ * Single-threaded synthesis queue.
233
412
  *
234
- * @param configPath - Path to config JSON file.
235
- * @returns Validated ServiceConfig.
413
+ * Only one synthesis runs at a time. Priority items are inserted at the
414
+ * front of the queue. Duplicate paths are rejected with their current
415
+ * position returned.
236
416
  */
237
- declare function loadServiceConfig(configPath: string): ServiceConfig;
417
+ declare class SynthesisQueue {
418
+ private queue;
419
+ private currentItem;
420
+ private processing;
421
+ private logger;
422
+ private onEnqueueCallback;
423
+ /**
424
+ * Create a new SynthesisQueue.
425
+ *
426
+ * @param logger - Pino logger instance.
427
+ */
428
+ constructor(logger: Logger);
429
+ /**
430
+ * Set a callback to invoke when a new (non-duplicate) item is enqueued.
431
+ */
432
+ onEnqueue(callback: () => void): void;
433
+ /**
434
+ * Add a path to the synthesis queue.
435
+ *
436
+ * @param path - Meta path to synthesize.
437
+ * @param priority - If true, insert at front of queue.
438
+ * @returns Position and whether the path was already queued.
439
+ */
440
+ enqueue(path: string, priority?: boolean): EnqueueResult;
441
+ /**
442
+ * Remove and return the next item from the queue.
443
+ *
444
+ * @returns The next QueueItem, or undefined if the queue is empty.
445
+ */
446
+ dequeue(): QueueItem | undefined;
447
+ /** Mark the currently-running synthesis as complete. */
448
+ complete(): void;
449
+ /** Number of items waiting in the queue (excludes current). */
450
+ get depth(): number;
451
+ /** The item currently being synthesized, or null. */
452
+ get current(): QueueItem | null;
453
+ /** A shallow copy of the queued items. */
454
+ get items(): QueueItem[];
455
+ /** A shallow copy of the pending items (alias for items). */
456
+ get pending(): QueueItem[];
457
+ /**
458
+ * Remove all pending items from the queue.
459
+ *
460
+ * Does not affect the currently-running item.
461
+ *
462
+ * @returns The number of items removed.
463
+ */
464
+ clear(): number;
465
+ /**
466
+ * Check whether a path is in the queue or currently being synthesized.
467
+ *
468
+ * @param path - Meta path to look up.
469
+ * @returns True if the path is queued or currently running.
470
+ */
471
+ has(path: string): boolean;
472
+ /**
473
+ * Get the 0-indexed position of a path in the queue.
474
+ *
475
+ * @param path - Meta path to look up.
476
+ * @returns Position index, or null if not found in the queue.
477
+ */
478
+ getPosition(path: string): number | null;
479
+ /**
480
+ * Return a snapshot of queue state for the /status endpoint.
481
+ *
482
+ * @returns Queue depth and item list.
483
+ */
484
+ getState(): QueueState;
485
+ /**
486
+ * Process queued items one at a time until the queue is empty.
487
+ *
488
+ * Re-entry is prevented: if already processing, the call returns
489
+ * immediately. Errors are logged and do not block subsequent items.
490
+ *
491
+ * @param synthesizeFn - Async function that performs synthesis for a path.
492
+ */
493
+ processQueue(synthesizeFn: (path: string) => Promise<void>): Promise<void>;
494
+ }
238
495
 
239
496
  /**
240
- * Per-cycle context package computed by the orchestrator.
497
+ * Virtual rule registration with jeeves-watcher.
241
498
  *
242
- * Shared inputs that multiple subprocesses need are computed once
243
- * and serialized into each subprocess's task prompt.
499
+ * Service registers inference rules at startup (with retry) and
500
+ * re-registers opportunistically when watcher restart is detected.
244
501
  *
245
- * @module interfaces/MetaContext
502
+ * @module rules
246
503
  */
504
+
247
505
  /**
248
- * Context package for a single synthesis cycle.
506
+ * Manages virtual rule registration with watcher.
249
507
  *
250
- * The orchestrator computes this once per cycle from the meta path,
251
- * ownership tree, watcher walk results, and filesystem reads.
508
+ * - Registers at startup with exponential retry
509
+ * - Tracks watcher uptime for restart detection
510
+ * - Re-registers opportunistically when uptime decreases
252
511
  */
253
- interface MetaContext {
254
- /** Absolute path to the .meta directory. */
255
- path: string;
256
- /** All files in scope (absolute paths). */
257
- scopeFiles: string[];
258
- /** Files changed since _generatedAt (absolute paths). */
259
- deltaFiles: string[];
260
- /** Child _content outputs, keyed by relative path. */
261
- childMetas: Record<string, unknown>;
262
- /** Cross-referenced meta _content outputs, keyed by owner path. */
263
- crossRefMetas: Record<string, unknown>;
264
- /** _content from the last cycle, or null on first run. */
265
- previousContent: string | null;
266
- /** _feedback from the last cycle, or null on first run. */
267
- previousFeedback: string | null;
268
- /** Current _steer value, or null if unset. */
269
- steer: string | null;
270
- /** _state from the last cycle, or null on first run. */
271
- previousState: unknown;
272
- /** Archive snapshot file paths (for steer change detection, etc.). */
273
- archives: string[];
512
+ declare class RuleRegistrar {
513
+ private readonly config;
514
+ private readonly logger;
515
+ private readonly watcherClient;
516
+ private lastWatcherUptime;
517
+ private registered;
518
+ constructor(config: MetaConfig, logger: Logger, watcher: WatcherClient);
519
+ /** Whether rules have been successfully registered. */
520
+ get isRegistered(): boolean;
521
+ /**
522
+ * Register rules with watcher. Retries with exponential backoff.
523
+ * Non-blocking logs errors but never throws.
524
+ */
525
+ register(): Promise<void>;
526
+ /**
527
+ * Check watcher uptime and re-register if it decreased (restart detected).
528
+ *
529
+ * @param currentUptime - Current watcher uptime in seconds.
530
+ */
531
+ checkAndReregister(currentUptime: number): Promise<void>;
274
532
  }
275
533
 
276
534
  /**
277
- * Pluggable executor interface for LLM subprocess invocation.
535
+ * HTTP implementation of the WatcherClient interface.
278
536
  *
279
- * @module interfaces/MetaExecutor
537
+ * Talks to jeeves-watcher's POST /walk and POST /rules/register endpoints
538
+ * with retry and exponential backoff.
539
+ *
540
+ * @module watcher-client/HttpWatcherClient
280
541
  */
281
- /** Options for spawning a synthesis subprocess. */
282
- interface MetaSpawnOptions {
283
- /** Model override for this subprocess. */
284
- model?: string;
285
- /** Timeout in seconds. */
286
- timeout?: number;
287
- /** Label for the spawned session. */
288
- label?: string;
289
- /** Thinking level (e.g. "low", "medium", "high"). */
290
- thinking?: string;
542
+
543
+ /** Options for creating an HttpWatcherClient. */
544
+ interface HttpWatcherClientOptions {
545
+ /** Base URL for the watcher service (e.g. "http://localhost:1936"). */
546
+ baseUrl: string;
547
+ /** Maximum retry attempts for transient failures. Default: 3. */
548
+ maxRetries?: number;
549
+ /** Base delay in ms for exponential backoff. Default: 1000. */
550
+ backoffBaseMs?: number;
551
+ /** Multiplier for backoff. Default: 4 (1s, 4s, 16s). */
552
+ backoffFactor?: number;
553
+ /** Per-request timeout in ms. Default: 10000. */
554
+ timeoutMs?: number;
291
555
  }
292
- /** Result of a spawn call, including optional token usage. */
293
- interface MetaSpawnResult {
294
- /** Subprocess output text. */
295
- output: string;
296
- /** Token count for this call, if available from the executor. */
297
- tokens?: number;
556
+ /**
557
+ * HTTP-based WatcherClient implementation with retry.
558
+ */
559
+ declare class HttpWatcherClient implements WatcherClient {
560
+ private readonly baseUrl;
561
+ private readonly maxRetries;
562
+ private readonly backoffBaseMs;
563
+ private readonly backoffFactor;
564
+ private readonly timeoutMs;
565
+ constructor(options: HttpWatcherClientOptions);
566
+ /** POST JSON with retry. */
567
+ private post;
568
+ registerRules(source: string, rules: InferenceRuleSpec[]): Promise<void>;
569
+ walk(globs: string[]): Promise<string[]>;
570
+ scan(request: WatcherScanRequest): Promise<WatcherScanResult>;
298
571
  }
572
+
299
573
  /**
300
- * Interface for spawning synthesis subprocesses.
574
+ * Croner-based scheduler that discovers the stalest meta candidate each tick
575
+ * and enqueues it for synthesis.
301
576
  *
302
- * The executor abstracts the LLM invocation mechanism. The orchestrator
303
- * calls spawn() sequentially for architect, builder, and critic steps.
304
- * Each call blocks until the subprocess completes and returns its result.
577
+ * @module scheduler
305
578
  */
306
- interface MetaExecutor {
579
+
580
+ /**
581
+ * Periodic scheduler that discovers stale meta candidates and enqueues them.
582
+ *
583
+ * Supports adaptive backoff when no candidates are found and hot-reloadable
584
+ * cron expressions via {@link Scheduler.updateSchedule}.
585
+ */
586
+ declare class Scheduler {
587
+ private job;
588
+ private backoffMultiplier;
589
+ private tickCount;
590
+ private readonly config;
591
+ private readonly queue;
592
+ private readonly logger;
593
+ private readonly watcher;
594
+ private registrar;
595
+ private currentExpression;
596
+ constructor(config: ServiceConfig, queue: SynthesisQueue, logger: Logger, watcher: HttpWatcherClient);
597
+ /** Set the rule registrar for watcher restart detection. */
598
+ setRegistrar(registrar: RuleRegistrar): void;
599
+ /** Start the cron job. */
600
+ start(): void;
601
+ /** Stop the cron job. */
602
+ stop(): void;
603
+ /** Hot-reload the cron schedule expression. */
604
+ updateSchedule(expression: string): void;
605
+ /** Reset backoff multiplier (call after successful synthesis). */
606
+ resetBackoff(): void;
607
+ /** Whether the scheduler is currently running. */
608
+ get isRunning(): boolean;
609
+ /** Next scheduled tick time, or null if not running. */
610
+ get nextRunAt(): Date | null;
307
611
  /**
308
- * Spawn a subprocess with the given task prompt.
612
+ * Single tick: discover stalest candidate and enqueue it.
309
613
  *
310
- * @param task - Full task prompt for the subprocess.
311
- * @param options - Optional model and timeout overrides.
312
- * @returns The subprocess result with output and optional token count.
614
+ * Skips if the queue is currently processing. Applies adaptive backoff
615
+ * when no candidates are found.
313
616
  */
314
- spawn(task: string, options?: MetaSpawnOptions): Promise<MetaSpawnResult>;
617
+ private tick;
618
+ /**
619
+ * Discover the stalest meta candidate via watcher.
620
+ */
621
+ private discoverStalest;
315
622
  }
316
623
 
317
624
  /**
318
- * Abstraction over the jeeves-watcher HTTP API.
625
+ * Shared live config hot-reload support.
319
626
  *
320
- * The service uses this for filesystem enumeration (POST /walk)
321
- * and virtual rule registration (POST /rules/register).
627
+ * Used by both file-watch reloads in bootstrap and POST /config/apply
628
+ * via the component descriptor's onConfigApply callback.
322
629
  *
323
- * @module interfaces/WatcherClient
630
+ * @module configHotReload
324
631
  */
325
- /** An inference rule to register with the watcher. */
326
- interface InferenceRuleSpec {
327
- /** Rule name. */
328
- name: string;
329
- /** Rule description. */
330
- description: string;
331
- /** JSON Schema match criteria. */
332
- match: Record<string, unknown>;
333
- /** Schema array with set keywords. */
334
- schema: unknown[];
335
- /** Declarative render config. */
336
- render?: Record<string, unknown>;
337
- /** Handlebars template name. */
338
- template?: string;
339
- /** Render output format. */
340
- renderAs?: string;
341
- }
632
+
633
+ /**
634
+ * Fields that require a service restart to take effect.
635
+ *
636
+ * Shared between the descriptor's `onConfigApply` and the file-watcher
637
+ * hot-reload in `bootstrap.ts`.
638
+ */
639
+ declare const RESTART_REQUIRED_FIELDS: readonly ["port", "host", "watcherUrl", "gatewayUrl", "gatewayApiKey", "defaultArchitect", "defaultCritic"];
640
+
641
+ /**
642
+ * Load and resolve jeeves-meta service config.
643
+ *
644
+ * Supports \@file: indirection and environment-variable substitution (dollar-brace pattern).
645
+ *
646
+ * @module configLoader
647
+ */
648
+
649
+ /**
650
+ * Migrate legacy config path to the new canonical location.
651
+ *
652
+ * If the old path `{configRoot}/jeeves-meta.config.json` exists and the new
653
+ * path `{configRoot}/jeeves-meta/config.json` does NOT exist, copies the file
654
+ * to the new location and logs a warning.
655
+ *
656
+ * @param configRoot - Root directory for configuration files.
657
+ * @param warn - Optional callback for logging the migration warning.
658
+ */
659
+ declare function migrateConfigPath(configRoot: string, warn?: (msg: string) => void): void;
660
+ /**
661
+ * Resolve config path from --config flag or JEEVES_META_CONFIG env var.
662
+ *
663
+ * @param args - CLI arguments (process.argv.slice(2)).
664
+ * @returns Resolved config path.
665
+ * @throws If no config path found.
666
+ */
667
+ declare function resolveConfigPath(args: string[]): string;
668
+ /**
669
+ * Load service config from a JSON file.
670
+ *
671
+ * Resolves \@file: references for defaultArchitect and defaultCritic,
672
+ * and substitutes environment-variable placeholders throughout.
673
+ *
674
+ * @param configPath - Path to config JSON file.
675
+ * @returns Validated ServiceConfig.
676
+ */
677
+ declare function loadServiceConfig(configPath: string): ServiceConfig;
678
+
342
679
  /**
343
- * Interface for watcher HTTP operations.
680
+ * Jeeves component descriptor for jeeves-meta.
344
681
  *
345
- * Implementations handle retry with backoff internally.
682
+ * Single source of truth consumed by the service CLI, plugin writer, and
683
+ * config-apply pipeline.
684
+ *
685
+ * @module descriptor
346
686
  */
347
- interface WatcherClient {
348
- /**
349
- * Register virtual inference rules with the watcher.
350
- *
351
- * @param source - Source identifier (e.g. 'jeeves-meta').
352
- * @param rules - Array of inference rules to register.
353
- */
354
- registerRules(source: string, rules: InferenceRuleSpec[]): Promise<void>;
355
- /**
356
- * Walk filesystem using glob patterns.
357
- *
358
- * @param globs - Array of glob patterns to match against.
359
- * @returns Promise resolving to array of matching file paths.
360
- */
361
- walk(globs: string[]): Promise<string[]>;
362
- }
687
+
688
+ /**
689
+ * Parsed jeeves-meta component descriptor.
690
+ */
691
+ declare const metaDescriptor: JeevesComponentDescriptor;
363
692
 
364
693
  /**
365
694
  * Types for meta discovery and ownership tree.
@@ -731,11 +1060,16 @@ declare class GatewayExecutor implements MetaExecutor {
731
1060
  private readonly apiKey;
732
1061
  private readonly pollIntervalMs;
733
1062
  private readonly workspaceDir;
1063
+ private controller;
734
1064
  constructor(options?: GatewayExecutorOptions);
1065
+ /** Remove a temp output file if it exists. */
1066
+ private cleanupOutputFile;
735
1067
  /** Invoke a gateway tool via the /tools/invoke HTTP endpoint. */
736
1068
  private invoke;
737
1069
  /** Look up totalTokens for a session via sessions_list. */
738
1070
  private getSessionTokens;
1071
+ /** Abort the currently running spawn, if any. */
1072
+ abort(): void;
739
1073
  spawn(task: string, options?: MetaSpawnOptions): Promise<MetaSpawnResult>;
740
1074
  }
741
1075
 
@@ -1065,239 +1399,6 @@ declare function isArchitectTriggered(meta: MetaJson, structureChanged: boolean,
1065
1399
  */
1066
1400
  declare function hasSteerChanged(currentSteer: string | undefined, archiveSteer: string | undefined, hasArchive: boolean): boolean;
1067
1401
 
1068
- /**
1069
- * Single-threaded synthesis queue with priority support and deduplication.
1070
- *
1071
- * The scheduler enqueues the stalest candidate each tick. HTTP-triggered
1072
- * synthesis requests get priority (inserted at front). A path appears at
1073
- * most once in the queue; re-triggering returns the current position.
1074
- *
1075
- * @module queue
1076
- */
1077
-
1078
- /** A queued synthesis work item. */
1079
- interface QueueItem {
1080
- path: string;
1081
- priority: boolean;
1082
- enqueuedAt: string;
1083
- }
1084
- /** Result returned by {@link SynthesisQueue.enqueue}. */
1085
- interface EnqueueResult {
1086
- position: number;
1087
- alreadyQueued: boolean;
1088
- }
1089
- /** Snapshot of queue state for the /status endpoint. */
1090
- interface QueueState {
1091
- depth: number;
1092
- items: Array<{
1093
- path: string;
1094
- priority: boolean;
1095
- enqueuedAt: string;
1096
- }>;
1097
- }
1098
- /**
1099
- * Single-threaded synthesis queue.
1100
- *
1101
- * Only one synthesis runs at a time. Priority items are inserted at the
1102
- * front of the queue. Duplicate paths are rejected with their current
1103
- * position returned.
1104
- */
1105
- declare class SynthesisQueue {
1106
- private queue;
1107
- private currentItem;
1108
- private processing;
1109
- private logger;
1110
- private onEnqueueCallback;
1111
- /**
1112
- * Create a new SynthesisQueue.
1113
- *
1114
- * @param logger - Pino logger instance.
1115
- */
1116
- constructor(logger: Logger);
1117
- /**
1118
- * Set a callback to invoke when a new (non-duplicate) item is enqueued.
1119
- */
1120
- onEnqueue(callback: () => void): void;
1121
- /**
1122
- * Add a path to the synthesis queue.
1123
- *
1124
- * @param path - Meta path to synthesize.
1125
- * @param priority - If true, insert at front of queue.
1126
- * @returns Position and whether the path was already queued.
1127
- */
1128
- enqueue(path: string, priority?: boolean): EnqueueResult;
1129
- /**
1130
- * Remove and return the next item from the queue.
1131
- *
1132
- * @returns The next QueueItem, or undefined if the queue is empty.
1133
- */
1134
- dequeue(): QueueItem | undefined;
1135
- /** Mark the currently-running synthesis as complete. */
1136
- complete(): void;
1137
- /** Number of items waiting in the queue (excludes current). */
1138
- get depth(): number;
1139
- /** The item currently being synthesized, or null. */
1140
- get current(): QueueItem | null;
1141
- /** A shallow copy of the queued items. */
1142
- get items(): QueueItem[];
1143
- /**
1144
- * Check whether a path is in the queue or currently being synthesized.
1145
- *
1146
- * @param path - Meta path to look up.
1147
- * @returns True if the path is queued or currently running.
1148
- */
1149
- has(path: string): boolean;
1150
- /**
1151
- * Get the 0-indexed position of a path in the queue.
1152
- *
1153
- * @param path - Meta path to look up.
1154
- * @returns Position index, or null if not found in the queue.
1155
- */
1156
- getPosition(path: string): number | null;
1157
- /**
1158
- * Return a snapshot of queue state for the /status endpoint.
1159
- *
1160
- * @returns Queue depth and item list.
1161
- */
1162
- getState(): QueueState;
1163
- /**
1164
- * Process queued items one at a time until the queue is empty.
1165
- *
1166
- * Re-entry is prevented: if already processing, the call returns
1167
- * immediately. Errors are logged and do not block subsequent items.
1168
- *
1169
- * @param synthesizeFn - Async function that performs synthesis for a path.
1170
- */
1171
- processQueue(synthesizeFn: (path: string) => Promise<void>): Promise<void>;
1172
- }
1173
-
1174
- /**
1175
- * Virtual rule registration with jeeves-watcher.
1176
- *
1177
- * Service registers inference rules at startup (with retry) and
1178
- * re-registers opportunistically when watcher restart is detected.
1179
- *
1180
- * @module rules
1181
- */
1182
-
1183
- /**
1184
- * Manages virtual rule registration with watcher.
1185
- *
1186
- * - Registers at startup with exponential retry
1187
- * - Tracks watcher uptime for restart detection
1188
- * - Re-registers opportunistically when uptime decreases
1189
- */
1190
- declare class RuleRegistrar {
1191
- private readonly config;
1192
- private readonly logger;
1193
- private readonly watcherClient;
1194
- private lastWatcherUptime;
1195
- private registered;
1196
- constructor(config: MetaConfig, logger: Logger, watcher: WatcherClient);
1197
- /** Whether rules have been successfully registered. */
1198
- get isRegistered(): boolean;
1199
- /**
1200
- * Register rules with watcher. Retries with exponential backoff.
1201
- * Non-blocking — logs errors but never throws.
1202
- */
1203
- register(): Promise<void>;
1204
- /**
1205
- * Check watcher uptime and re-register if it decreased (restart detected).
1206
- *
1207
- * @param currentUptime - Current watcher uptime in seconds.
1208
- */
1209
- checkAndReregister(currentUptime: number): Promise<void>;
1210
- }
1211
-
1212
- /**
1213
- * HTTP implementation of the WatcherClient interface.
1214
- *
1215
- * Talks to jeeves-watcher's POST /walk and POST /rules/register endpoints
1216
- * with retry and exponential backoff.
1217
- *
1218
- * @module watcher-client/HttpWatcherClient
1219
- */
1220
-
1221
- /** Options for creating an HttpWatcherClient. */
1222
- interface HttpWatcherClientOptions {
1223
- /** Base URL for the watcher service (e.g. "http://localhost:1936"). */
1224
- baseUrl: string;
1225
- /** Maximum retry attempts for transient failures. Default: 3. */
1226
- maxRetries?: number;
1227
- /** Base delay in ms for exponential backoff. Default: 1000. */
1228
- backoffBaseMs?: number;
1229
- /** Multiplier for backoff. Default: 4 (1s, 4s, 16s). */
1230
- backoffFactor?: number;
1231
- /** Per-request timeout in ms. Default: 10000. */
1232
- timeoutMs?: number;
1233
- }
1234
- /**
1235
- * HTTP-based WatcherClient implementation with retry.
1236
- */
1237
- declare class HttpWatcherClient implements WatcherClient {
1238
- private readonly baseUrl;
1239
- private readonly maxRetries;
1240
- private readonly backoffBaseMs;
1241
- private readonly backoffFactor;
1242
- private readonly timeoutMs;
1243
- constructor(options: HttpWatcherClientOptions);
1244
- /** POST JSON with retry. */
1245
- private post;
1246
- registerRules(source: string, rules: InferenceRuleSpec[]): Promise<void>;
1247
- walk(globs: string[]): Promise<string[]>;
1248
- }
1249
-
1250
- /**
1251
- * Croner-based scheduler that discovers the stalest meta candidate each tick
1252
- * and enqueues it for synthesis.
1253
- *
1254
- * @module scheduler
1255
- */
1256
-
1257
- /**
1258
- * Periodic scheduler that discovers stale meta candidates and enqueues them.
1259
- *
1260
- * Supports adaptive backoff when no candidates are found and hot-reloadable
1261
- * cron expressions via {@link Scheduler.updateSchedule}.
1262
- */
1263
- declare class Scheduler {
1264
- private job;
1265
- private backoffMultiplier;
1266
- private tickCount;
1267
- private readonly config;
1268
- private readonly queue;
1269
- private readonly logger;
1270
- private readonly watcher;
1271
- private registrar;
1272
- private currentExpression;
1273
- constructor(config: ServiceConfig, queue: SynthesisQueue, logger: Logger, watcher: HttpWatcherClient);
1274
- /** Set the rule registrar for watcher restart detection. */
1275
- setRegistrar(registrar: RuleRegistrar): void;
1276
- /** Start the cron job. */
1277
- start(): void;
1278
- /** Stop the cron job. */
1279
- stop(): void;
1280
- /** Hot-reload the cron schedule expression. */
1281
- updateSchedule(expression: string): void;
1282
- /** Reset backoff multiplier (call after successful synthesis). */
1283
- resetBackoff(): void;
1284
- /** Whether the scheduler is currently running. */
1285
- get isRunning(): boolean;
1286
- /** Next scheduled tick time, or null if not running. */
1287
- get nextRunAt(): Date | null;
1288
- /**
1289
- * Single tick: discover stalest candidate and enqueue it.
1290
- *
1291
- * Skips if the queue is currently processing. Applies adaptive backoff
1292
- * when no candidates are found.
1293
- */
1294
- private tick;
1295
- /**
1296
- * Discover the stalest meta candidate via watcher.
1297
- */
1298
- private discoverStalest;
1299
- }
1300
-
1301
1402
  /**
1302
1403
  * Route registration for jeeves-meta service.
1303
1404
  *
@@ -1317,11 +1418,13 @@ interface RouteDeps {
1317
1418
  config: ServiceConfig;
1318
1419
  logger: Logger;
1319
1420
  queue: SynthesisQueue;
1320
- watcher: HttpWatcherClient;
1421
+ watcher: WatcherClient;
1321
1422
  scheduler: Scheduler | null;
1322
1423
  stats: ServiceStats;
1323
1424
  /** Rule registrar for reporting registration state in /status. */
1324
1425
  registrar?: RuleRegistrar;
1426
+ /** Executor instance for abort support. */
1427
+ executor?: Pick<GatewayExecutor, 'abort'>;
1325
1428
  /** Set to true during graceful shutdown. */
1326
1429
  shuttingDown?: boolean;
1327
1430
  }
@@ -1416,5 +1519,5 @@ declare function registerShutdownHandlers(deps: ShutdownDeps): void;
1416
1519
  */
1417
1520
  declare function startService(config: ServiceConfig, configPath?: string): Promise<void>;
1418
1521
 
1419
- export { DEFAULT_PORT, DEFAULT_PORT_STR, GatewayExecutor, HttpWatcherClient, ProgressReporter, RuleRegistrar, SERVICE_NAME, SERVICE_VERSION, Scheduler, SynthesisQueue, acquireLock, actualStaleness, buildArchitectTask, buildBuilderTask, buildContextPackage, buildCriticTask, buildOwnershipTree, cleanupStaleLocks, computeEffectiveStaleness, computeEma, computeStructureHash, createLogger, createServer, createSnapshot, discoverMetas, filterInScope, findNode, formatProgressEvent, getScopePrefix, hasSteerChanged, isArchitectTriggered, isLocked, isStale, listArchiveFiles, listMetas, loadServiceConfig, mergeAndWrite, metaConfigSchema, metaErrorSchema, metaJsonSchema, normalizePath, orchestrate, parseArchitectOutput, parseBuilderOutput, parseCriticOutput, pruneArchive, readLatestArchive, readLockState, registerRoutes, registerShutdownHandlers, releaseLock, resolveConfigPath, resolveMetaDir, selectCandidate, serviceConfigSchema, sleep, startService, toMetaError, verifyRuleApplication };
1420
- export type { BuilderOutput, EnqueueResult, GatewayExecutorOptions, HttpWatcherClientOptions, InferenceRuleSpec, LockState, LoggerConfig, MergeOptions, MetaConfig, MetaContext, MetaEntry, MetaError, MetaExecutor, MetaJson, MetaListResult, MetaListSummary, MetaNode, MetaSpawnOptions, MetaSpawnResult, MinimalLogger, OrchestrateResult, OwnershipTree, ProgressCallback, ProgressEvent, ProgressPhase, ProgressReporterConfig, QueueItem, QueueState, RouteDeps, ServerOptions, ServiceConfig, ServiceStats, StalenessCandidate, WatcherClient };
1522
+ export { DEFAULT_PORT, DEFAULT_PORT_STR, GatewayExecutor, HttpWatcherClient, ProgressReporter, RESTART_REQUIRED_FIELDS, RuleRegistrar, SERVICE_NAME, SERVICE_VERSION, Scheduler, SynthesisQueue, acquireLock, actualStaleness, buildArchitectTask, buildBuilderTask, buildContextPackage, buildCriticTask, buildOwnershipTree, cleanupStaleLocks, computeEffectiveStaleness, computeEma, computeStructureHash, createLogger, createServer, createSnapshot, discoverMetas, filterInScope, findNode, formatProgressEvent, getScopePrefix, hasSteerChanged, isArchitectTriggered, isLocked, isStale, listArchiveFiles, listMetas, loadServiceConfig, mergeAndWrite, metaConfigSchema, metaDescriptor, metaErrorSchema, metaJsonSchema, migrateConfigPath, normalizePath, orchestrate, parseArchitectOutput, parseBuilderOutput, parseCriticOutput, pruneArchive, readLatestArchive, readLockState, registerCustomCliCommands, registerRoutes, registerShutdownHandlers, releaseLock, resolveConfigPath, resolveMetaDir, selectCandidate, serviceConfigSchema, sleep, startService, toMetaError, verifyRuleApplication };
1523
+ export type { BuilderOutput, EnqueueResult, GatewayExecutorOptions, HttpWatcherClientOptions, InferenceRuleSpec, LockState, LoggerConfig, MergeOptions, MetaConfig, MetaContext, MetaEntry, MetaError, MetaExecutor, MetaJson, MetaListResult, MetaListSummary, MetaNode, MetaSpawnOptions, MetaSpawnResult, MinimalLogger, OrchestrateResult, OwnershipTree, ProgressCallback, ProgressEvent, ProgressPhase, ProgressReporterConfig, QueueItem, QueueState, RouteDeps, ServerOptions, ServiceConfig, ServiceStats, StalenessCandidate, WatcherClient, WatcherScanPoint, WatcherScanRequest, WatcherScanResult };