@karmaniverous/jeeves-meta 0.15.4 → 0.15.6
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/archive/index.d.ts +10 -0
- package/dist/archive/listArchive.d.ts +12 -0
- package/dist/archive/prune.d.ts +14 -0
- package/dist/archive/readArchive.d.ts +30 -0
- package/dist/archive/readLatest.d.ts +13 -0
- package/dist/archive/snapshot.d.ts +17 -0
- package/dist/bootstrap.d.ts +15 -0
- package/dist/cache.d.ts +22 -0
- package/dist/cli/jeeves-meta/index.js +199 -95
- package/dist/cli.d.ts +10 -0
- package/dist/configHotReload.d.ts +30 -0
- package/dist/configLoader.d.ts +37 -0
- package/dist/constants.d.ts +13 -0
- package/dist/customCliCommands.d.ts +13 -0
- package/dist/descriptor.d.ts +19 -0
- package/dist/discovery/buildMinimalNode.d.ts +22 -0
- package/dist/discovery/computeSummary.d.ts +17 -0
- package/dist/discovery/discoverMetas.d.ts +19 -0
- package/dist/discovery/index.d.ts +11 -0
- package/dist/discovery/listMetas.d.ts +63 -0
- package/dist/discovery/ownershipTree.d.ts +25 -0
- package/dist/discovery/scope.d.ts +47 -0
- package/dist/discovery/types.d.ts +25 -0
- package/dist/ema.d.ts +14 -0
- package/dist/errors.d.ts +15 -0
- package/dist/escapeGlob.d.ts +23 -0
- package/dist/executor/GatewayExecutor.d.ts +48 -0
- package/dist/executor/SpawnAbortedError.d.ts +9 -0
- package/dist/executor/SpawnTimeoutError.d.ts +13 -0
- package/dist/executor/index.d.ts +8 -0
- package/dist/index.d.ts +34 -1580
- package/dist/index.js +182 -109
- package/dist/interfaces/MetaContext.d.ts +36 -0
- package/dist/interfaces/MetaExecutor.d.ts +46 -0
- package/dist/interfaces/WatcherClient.d.ts +75 -0
- package/dist/interfaces/index.d.ts +8 -0
- package/dist/lock.d.ts +70 -0
- package/dist/logger/index.d.ts +27 -0
- package/dist/mtimeFilter.d.ts +26 -0
- package/dist/normalizePath.d.ts +6 -0
- package/dist/orchestrator/buildTask.d.ts +38 -0
- package/dist/orchestrator/contextPackage.d.ts +30 -0
- package/dist/orchestrator/index.d.ts +10 -0
- package/dist/orchestrator/orchestratePhase.d.ts +38 -0
- package/dist/orchestrator/parseOutput.d.ts +41 -0
- package/dist/orchestrator/runPhase.d.ts +40 -0
- package/dist/phaseState/derivePhaseState.d.ts +41 -0
- package/dist/phaseState/index.d.ts +9 -0
- package/dist/phaseState/invalidate.d.ts +41 -0
- package/dist/phaseState/phaseScheduler.d.ts +57 -0
- package/dist/phaseState/phaseTransitions.d.ts +83 -0
- package/dist/progress/index.d.ts +38 -0
- package/dist/prompts/index.d.ts +15 -0
- package/dist/queue/index.d.ts +131 -0
- package/dist/readMetaJson.d.ts +17 -0
- package/dist/routes/__testUtils.d.ts +37 -0
- package/dist/routes/config.d.ts +11 -0
- package/dist/routes/configApply.d.ts +13 -0
- package/dist/routes/index.d.ts +50 -0
- package/dist/routes/metas.d.ts +9 -0
- package/dist/routes/metasUpdate.d.ts +11 -0
- package/dist/routes/preview.d.ts +8 -0
- package/dist/routes/queue.d.ts +13 -0
- package/dist/routes/seed.d.ts +8 -0
- package/dist/routes/status.d.ts +13 -0
- package/dist/routes/synthesize.d.ts +12 -0
- package/dist/routes/unlock.d.ts +8 -0
- package/dist/rules/healthCheck.d.ts +36 -0
- package/dist/rules/index.d.ts +39 -0
- package/dist/rules/verify.d.ts +22 -0
- package/dist/scheduler/index.d.ts +66 -0
- package/dist/scheduling/index.d.ts +7 -0
- package/dist/scheduling/staleness.d.ts +68 -0
- package/dist/scheduling/weightedFormula.d.ts +38 -0
- package/dist/schema/config.d.ts +54 -0
- package/dist/schema/error.d.ts +6 -0
- package/dist/schema/index.d.ts +8 -0
- package/dist/schema/meta.d.ts +71 -0
- package/dist/seed/autoSeed.d.ts +30 -0
- package/dist/seed/createMeta.d.ts +38 -0
- package/dist/seed/index.d.ts +7 -0
- package/dist/server.d.ts +24 -0
- package/dist/shutdown/index.d.ts +33 -0
- package/dist/structureHash.d.ts +15 -0
- package/dist/watcher-client/HttpWatcherClient.d.ts +38 -0
- package/dist/watcher-client/index.d.ts +6 -0
- package/package.json +16 -26
|
@@ -0,0 +1,131 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Hybrid 3-layer synthesis queue.
|
|
3
|
+
*
|
|
4
|
+
* Layer 1: Current — the single item currently executing (at most one).
|
|
5
|
+
* Layer 2: Overrides — items manually enqueued via POST /synthesize with path.
|
|
6
|
+
* FIFO among overrides, ahead of automatic candidates.
|
|
7
|
+
* Layer 3: Automatic — computed on read, not persisted. All metas with a
|
|
8
|
+
* pending phase, ranked by scheduler priority.
|
|
9
|
+
*
|
|
10
|
+
* Legacy: `pending` array is the union of overrides + automatic.
|
|
11
|
+
*
|
|
12
|
+
* @module queue
|
|
13
|
+
*/
|
|
14
|
+
import type { Logger } from 'pino';
|
|
15
|
+
import type { PhaseName } from '../schema/meta.js';
|
|
16
|
+
/** A queued synthesis work item. */
|
|
17
|
+
export interface QueueItem {
|
|
18
|
+
path: string;
|
|
19
|
+
priority: boolean;
|
|
20
|
+
enqueuedAt: string;
|
|
21
|
+
}
|
|
22
|
+
/** An override entry in the explicit queue layer. */
|
|
23
|
+
export interface OverrideEntry {
|
|
24
|
+
path: string;
|
|
25
|
+
enqueuedAt: string;
|
|
26
|
+
}
|
|
27
|
+
/** The currently executing item with phase info. */
|
|
28
|
+
export interface CurrentItem {
|
|
29
|
+
path: string;
|
|
30
|
+
phase: PhaseName;
|
|
31
|
+
startedAt: string;
|
|
32
|
+
}
|
|
33
|
+
/** Result returned by {@link SynthesisQueue.enqueue}. */
|
|
34
|
+
export interface EnqueueResult {
|
|
35
|
+
position: number;
|
|
36
|
+
alreadyQueued: boolean;
|
|
37
|
+
}
|
|
38
|
+
/** Snapshot of queue state for the /status endpoint. */
|
|
39
|
+
export interface QueueState {
|
|
40
|
+
depth: number;
|
|
41
|
+
items: Array<{
|
|
42
|
+
path: string;
|
|
43
|
+
priority: boolean;
|
|
44
|
+
enqueuedAt: string;
|
|
45
|
+
}>;
|
|
46
|
+
}
|
|
47
|
+
/**
|
|
48
|
+
* Hybrid 3-layer synthesis queue.
|
|
49
|
+
*
|
|
50
|
+
* Only one synthesis runs at a time. Override items (explicit triggers)
|
|
51
|
+
* take priority over automatic candidates.
|
|
52
|
+
*/
|
|
53
|
+
export declare class SynthesisQueue {
|
|
54
|
+
/** Legacy queue (used by processQueue for backward compat). */
|
|
55
|
+
private queue;
|
|
56
|
+
private currentItem;
|
|
57
|
+
private processing;
|
|
58
|
+
private logger;
|
|
59
|
+
private onEnqueueCallback;
|
|
60
|
+
/** Explicit override entries (3-layer model). */
|
|
61
|
+
private overrideEntries;
|
|
62
|
+
/** Currently executing item with phase info (3-layer model). */
|
|
63
|
+
private currentPhaseItem;
|
|
64
|
+
constructor(logger: Logger);
|
|
65
|
+
/** Set a callback to invoke when a new (non-duplicate) item is enqueued. */
|
|
66
|
+
onEnqueue(callback: () => void): void;
|
|
67
|
+
/**
|
|
68
|
+
* Add an explicit override entry (from POST /synthesize with path).
|
|
69
|
+
* Deduped by path. Returns position and whether already queued.
|
|
70
|
+
*/
|
|
71
|
+
enqueueOverride(path: string): EnqueueResult;
|
|
72
|
+
/** Dequeue the next override entry, or undefined if empty. */
|
|
73
|
+
dequeueOverride(): OverrideEntry | undefined;
|
|
74
|
+
/** Get all override entries (shallow copy). */
|
|
75
|
+
get overrides(): OverrideEntry[];
|
|
76
|
+
/** Clear all override entries. Returns count removed. */
|
|
77
|
+
clearOverrides(): number;
|
|
78
|
+
/** Check if a path is in the override layer. */
|
|
79
|
+
hasOverride(path: string): boolean;
|
|
80
|
+
/** Set the currently executing phase item. */
|
|
81
|
+
setCurrentPhase(path: string, phase: PhaseName): void;
|
|
82
|
+
/** Clear the current phase item. */
|
|
83
|
+
clearCurrentPhase(): void;
|
|
84
|
+
/** The currently executing phase item, or null. */
|
|
85
|
+
get currentPhase(): CurrentItem | null;
|
|
86
|
+
/**
|
|
87
|
+
* Add a path to the synthesis queue.
|
|
88
|
+
*
|
|
89
|
+
* @param path - Meta path to synthesize.
|
|
90
|
+
* @param priority - If true, insert at front of queue.
|
|
91
|
+
* @returns Position and whether the path was already queued.
|
|
92
|
+
*/
|
|
93
|
+
enqueue(path: string, priority?: boolean): EnqueueResult;
|
|
94
|
+
/** Remove and return the next item from the queue. */
|
|
95
|
+
dequeue(): QueueItem | undefined;
|
|
96
|
+
/** Mark the currently-running synthesis as complete. */
|
|
97
|
+
complete(): void;
|
|
98
|
+
/** Number of items waiting in the queue (excludes current). */
|
|
99
|
+
get depth(): number;
|
|
100
|
+
/** The item currently being synthesized, or null. */
|
|
101
|
+
get current(): QueueItem | null;
|
|
102
|
+
/** A shallow copy of the queued items. */
|
|
103
|
+
get items(): QueueItem[];
|
|
104
|
+
/** A shallow copy of the pending items (alias for items). */
|
|
105
|
+
get pending(): QueueItem[];
|
|
106
|
+
/**
|
|
107
|
+
* Remove all pending items from the queue.
|
|
108
|
+
* Does not affect the currently-running item.
|
|
109
|
+
*
|
|
110
|
+
* @returns The number of items removed.
|
|
111
|
+
*/
|
|
112
|
+
clear(): number;
|
|
113
|
+
/** Check whether a path is in the queue or currently being synthesized. */
|
|
114
|
+
has(path: string): boolean;
|
|
115
|
+
/** Get the 0-indexed position of a path in the queue. */
|
|
116
|
+
getPosition(path: string): number | null;
|
|
117
|
+
/** Dequeue the next item: overrides first, then legacy queue. */
|
|
118
|
+
private nextItem;
|
|
119
|
+
/** Return a snapshot of queue state for the /status endpoint. */
|
|
120
|
+
getState(): QueueState;
|
|
121
|
+
/**
|
|
122
|
+
* Process queued items one at a time until all queues are empty.
|
|
123
|
+
*
|
|
124
|
+
* Override entries are processed first (FIFO), then legacy queue items.
|
|
125
|
+
* Re-entry is prevented: if already processing, the call returns
|
|
126
|
+
* immediately. Errors are logged and do not block subsequent items.
|
|
127
|
+
*
|
|
128
|
+
* @param synthesizeFn - Async function that performs synthesis for a path.
|
|
129
|
+
*/
|
|
130
|
+
processQueue(synthesizeFn: (path: string) => Promise<void>): Promise<void>;
|
|
131
|
+
}
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Read and parse a meta.json file from a `.meta/` directory.
|
|
3
|
+
*
|
|
4
|
+
* Shared utility to eliminate repeated `JSON.parse(readFileSync(...))` across
|
|
5
|
+
* discovery, orchestration, and route handlers.
|
|
6
|
+
*
|
|
7
|
+
* @module readMetaJson
|
|
8
|
+
*/
|
|
9
|
+
import type { MetaJson } from './schema/index.js';
|
|
10
|
+
/**
|
|
11
|
+
* Read and parse a meta.json file from a `.meta/` directory path (async).
|
|
12
|
+
*
|
|
13
|
+
* @param metaPath - Path to the `.meta/` directory.
|
|
14
|
+
* @returns Parsed meta.json content.
|
|
15
|
+
* @throws If the file doesn't exist or contains invalid JSON.
|
|
16
|
+
*/
|
|
17
|
+
export declare function readMetaJson(metaPath: string): Promise<MetaJson>;
|
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Shared test utilities for route test files.
|
|
3
|
+
*
|
|
4
|
+
* Provides factories for RouteDeps, logger mocks, watcher mocks, and
|
|
5
|
+
* filesystem-based meta fixtures. Eliminates duplication across 9+ test files.
|
|
6
|
+
*
|
|
7
|
+
* @module routes/__testUtils
|
|
8
|
+
*/
|
|
9
|
+
import type { Logger } from 'pino';
|
|
10
|
+
import type { WatcherClient } from '../interfaces/index.js';
|
|
11
|
+
import type { RouteDeps } from './index.js';
|
|
12
|
+
/** Create a mock pino logger with all standard methods. */
|
|
13
|
+
export declare function makeTestLogger(): Logger;
|
|
14
|
+
/** Overrides for makeTestDeps — config can be partially specified. */
|
|
15
|
+
type TestDepsOverrides = Omit<Partial<RouteDeps>, 'config'> & {
|
|
16
|
+
config?: Partial<RouteDeps['config']>;
|
|
17
|
+
};
|
|
18
|
+
/** Create a RouteDeps object with sensible test defaults. */
|
|
19
|
+
export declare function makeTestDeps(overrides?: TestDepsOverrides): RouteDeps;
|
|
20
|
+
/**
|
|
21
|
+
* Create a mock WatcherClient that resolves walk() with given paths.
|
|
22
|
+
*
|
|
23
|
+
* @param metaJsonPaths - Paths to return from walk().
|
|
24
|
+
* @param scan - Optional custom scan mock (defaults to empty results).
|
|
25
|
+
*/
|
|
26
|
+
export declare function makeTestWatcher(metaJsonPaths?: string[], scan?: import("vitest").Mock<import("@vitest/spy").Procedure>): WatcherClient;
|
|
27
|
+
/** Create a mock WatcherClient that rejects walk() calls. */
|
|
28
|
+
export declare function makeFailingTestWatcher(): WatcherClient;
|
|
29
|
+
/**
|
|
30
|
+
* Create a .meta/meta.json on disk and return the meta.json path.
|
|
31
|
+
*
|
|
32
|
+
* @param ownerDir - The owner directory to create .meta/ in.
|
|
33
|
+
* @param meta - Additional meta fields (merged with default _id).
|
|
34
|
+
* @returns The path to the created meta.json file.
|
|
35
|
+
*/
|
|
36
|
+
export declare function createTestMeta(ownerDir: string, meta?: Record<string, unknown>): string;
|
|
37
|
+
export {};
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* GET /config — query service configuration with optional JSONPath.
|
|
3
|
+
*
|
|
4
|
+
* Replaces the old GET /config/validate endpoint with the core SDK's
|
|
5
|
+
* `createConfigQueryHandler()` for JSONPath support.
|
|
6
|
+
*
|
|
7
|
+
* @module routes/config
|
|
8
|
+
*/
|
|
9
|
+
import type { FastifyInstance } from 'fastify';
|
|
10
|
+
import type { RouteDeps } from './index.js';
|
|
11
|
+
export declare function registerConfigRoute(app: FastifyInstance, deps: RouteDeps): void;
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* POST /config/apply — apply a config patch using the runtime config path.
|
|
3
|
+
*
|
|
4
|
+
* The core SDK's `createConfigApplyHandler` derives the config path from
|
|
5
|
+
* `getComponentConfigDir()` which uses the npm global config root. This
|
|
6
|
+
* local implementation uses the actual runtime config path instead, so
|
|
7
|
+
* temp files are written alongside the active config file.
|
|
8
|
+
*
|
|
9
|
+
* @module routes/configApply
|
|
10
|
+
*/
|
|
11
|
+
import type { FastifyInstance } from 'fastify';
|
|
12
|
+
/** Register the POST /config/apply route. */
|
|
13
|
+
export declare function registerConfigApplyRoute(app: FastifyInstance, configPath?: string): void;
|
|
@@ -0,0 +1,50 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Route registration for jeeves-meta service.
|
|
3
|
+
*
|
|
4
|
+
* @module routes
|
|
5
|
+
*/
|
|
6
|
+
import type { FastifyInstance } from 'fastify';
|
|
7
|
+
import type { Logger } from 'pino';
|
|
8
|
+
import type { MetaCache } from '../cache.js';
|
|
9
|
+
import type { GatewayExecutor } from '../executor/index.js';
|
|
10
|
+
import type { WatcherClient } from '../interfaces/index.js';
|
|
11
|
+
import type { SynthesisQueue } from '../queue/index.js';
|
|
12
|
+
import type { RuleRegistrar } from '../rules/index.js';
|
|
13
|
+
import type { Scheduler } from '../scheduler/index.js';
|
|
14
|
+
import type { ServiceConfig } from '../schema/config.js';
|
|
15
|
+
/** Runtime stats tracked by the service. */
|
|
16
|
+
export interface ServiceStats {
|
|
17
|
+
totalSyntheses: number;
|
|
18
|
+
totalTokens: number;
|
|
19
|
+
totalErrors: number;
|
|
20
|
+
lastCycleDurationMs: number | null;
|
|
21
|
+
lastCycleAt: string | null;
|
|
22
|
+
}
|
|
23
|
+
/**
|
|
24
|
+
* Large generated fields excluded from detail/update response projections.
|
|
25
|
+
* Shared between metas detail and metasUpdate routes.
|
|
26
|
+
*/
|
|
27
|
+
export declare const DEFAULT_EXCLUDE_FIELDS: Set<string>;
|
|
28
|
+
/** Dependencies injected into route handlers. */
|
|
29
|
+
export interface RouteDeps {
|
|
30
|
+
config: ServiceConfig;
|
|
31
|
+
logger: Logger;
|
|
32
|
+
queue: SynthesisQueue;
|
|
33
|
+
watcher: WatcherClient;
|
|
34
|
+
scheduler: Scheduler | null;
|
|
35
|
+
stats: ServiceStats;
|
|
36
|
+
/** Cached listMetas results with TTL. */
|
|
37
|
+
cache: MetaCache;
|
|
38
|
+
/** Service readiness flag — false during startup. */
|
|
39
|
+
ready: boolean;
|
|
40
|
+
/** Rule registrar for reporting registration state in /status. */
|
|
41
|
+
registrar?: RuleRegistrar;
|
|
42
|
+
/** Executor instance for abort support. */
|
|
43
|
+
executor?: Pick<GatewayExecutor, 'abort'>;
|
|
44
|
+
/** Set to true during graceful shutdown. */
|
|
45
|
+
shuttingDown?: boolean;
|
|
46
|
+
/** Runtime config file path for config-apply. */
|
|
47
|
+
configPath?: string;
|
|
48
|
+
}
|
|
49
|
+
/** Register all HTTP routes on the Fastify instance. */
|
|
50
|
+
export declare function registerRoutes(app: FastifyInstance, deps: RouteDeps): void;
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* GET /metas — list metas with optional filters.
|
|
3
|
+
* GET /metas/:path — single meta detail.
|
|
4
|
+
*
|
|
5
|
+
* @module routes/metas
|
|
6
|
+
*/
|
|
7
|
+
import type { FastifyInstance } from 'fastify';
|
|
8
|
+
import { type RouteDeps } from './index.js';
|
|
9
|
+
export declare function registerMetasRoutes(app: FastifyInstance, deps: RouteDeps): void;
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* PATCH /metas/:path — update user-settable reserved properties on a meta.
|
|
3
|
+
*
|
|
4
|
+
* Supported fields: _steer, _emphasis, _depth, _crossRefs, _disabled.
|
|
5
|
+
* Set a field to null to remove it. Unknown keys are rejected.
|
|
6
|
+
*
|
|
7
|
+
* @module routes/metasUpdate
|
|
8
|
+
*/
|
|
9
|
+
import type { FastifyInstance } from 'fastify';
|
|
10
|
+
import { type RouteDeps } from './index.js';
|
|
11
|
+
export declare function registerMetasUpdateRoute(app: FastifyInstance, deps: RouteDeps): void;
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* GET /preview — dry-run synthesis preview.
|
|
3
|
+
*
|
|
4
|
+
* @module routes/preview
|
|
5
|
+
*/
|
|
6
|
+
import type { FastifyInstance } from 'fastify';
|
|
7
|
+
import type { RouteDeps } from './index.js';
|
|
8
|
+
export declare function registerPreviewRoute(app: FastifyInstance, deps: RouteDeps): void;
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Queue management and abort routes.
|
|
3
|
+
*
|
|
4
|
+
* - GET /queue — 3-layer queue model (current, overrides, automatic, pending)
|
|
5
|
+
* - POST /queue/clear — remove override entries only
|
|
6
|
+
* - POST /synthesize/abort — abort the current synthesis
|
|
7
|
+
*
|
|
8
|
+
* @module routes/queue
|
|
9
|
+
*/
|
|
10
|
+
import type { FastifyInstance } from 'fastify';
|
|
11
|
+
import type { RouteDeps } from './index.js';
|
|
12
|
+
/** Register queue management routes. */
|
|
13
|
+
export declare function registerQueueRoutes(app: FastifyInstance, deps: RouteDeps): void;
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* POST /seed — create a .meta/ directory with an empty meta.json.
|
|
3
|
+
*
|
|
4
|
+
* @module routes/seed
|
|
5
|
+
*/
|
|
6
|
+
import type { FastifyInstance } from 'fastify';
|
|
7
|
+
import type { RouteDeps } from './index.js';
|
|
8
|
+
export declare function registerSeedRoute(app: FastifyInstance, deps: RouteDeps): void;
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* GET /status — service health and status overview.
|
|
3
|
+
*
|
|
4
|
+
* Uses the core SDK's `createStatusHandler` factory with a custom
|
|
5
|
+
* `getHealth` callback that preserves all existing health details.
|
|
6
|
+
*
|
|
7
|
+
* @module routes/status
|
|
8
|
+
*/
|
|
9
|
+
import type { ServiceState } from '@karmaniverous/jeeves-meta-core';
|
|
10
|
+
import type { FastifyInstance } from 'fastify';
|
|
11
|
+
import type { RouteDeps } from './index.js';
|
|
12
|
+
export type { ServiceState };
|
|
13
|
+
export declare function registerStatusRoute(app: FastifyInstance, deps: RouteDeps): void;
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* POST /synthesize route handler.
|
|
3
|
+
*
|
|
4
|
+
* Path-targeted triggers create explicit override entries in the queue.
|
|
5
|
+
* Corpus-wide triggers discover the stalest candidate.
|
|
6
|
+
*
|
|
7
|
+
* @module routes/synthesize
|
|
8
|
+
*/
|
|
9
|
+
import type { FastifyInstance } from 'fastify';
|
|
10
|
+
import type { RouteDeps } from './index.js';
|
|
11
|
+
/** Register the POST /synthesize route. */
|
|
12
|
+
export declare function registerSynthesizeRoute(app: FastifyInstance, deps: RouteDeps): void;
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* POST /unlock — remove .lock from a .meta/ directory.
|
|
3
|
+
*
|
|
4
|
+
* @module routes/unlock
|
|
5
|
+
*/
|
|
6
|
+
import type { FastifyInstance } from 'fastify';
|
|
7
|
+
import type { RouteDeps } from './index.js';
|
|
8
|
+
export declare function registerUnlockRoute(app: FastifyInstance, deps: RouteDeps): void;
|
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Periodic watcher health check for rule registration resilience.
|
|
3
|
+
*
|
|
4
|
+
* Pings watcher `/status` on a configurable interval, detects restarts
|
|
5
|
+
* (uptime decrease), and re-registers virtual rules automatically.
|
|
6
|
+
* Independent of the synthesis scheduler.
|
|
7
|
+
*
|
|
8
|
+
* @module rules/healthCheck
|
|
9
|
+
*/
|
|
10
|
+
import type { Logger } from 'pino';
|
|
11
|
+
import type { RuleRegistrar } from './index.js';
|
|
12
|
+
/**
|
|
13
|
+
* Manages the periodic watcher health check loop.
|
|
14
|
+
*
|
|
15
|
+
* Starts a `setInterval` that pings the watcher and delegates
|
|
16
|
+
* restart detection to `RuleRegistrar.checkAndReregister()`.
|
|
17
|
+
*/
|
|
18
|
+
export declare class WatcherHealthCheck {
|
|
19
|
+
private readonly watcherUrl;
|
|
20
|
+
private readonly intervalMs;
|
|
21
|
+
private readonly registrar;
|
|
22
|
+
private readonly logger;
|
|
23
|
+
private handle;
|
|
24
|
+
constructor(opts: {
|
|
25
|
+
watcherUrl: string;
|
|
26
|
+
intervalMs: number;
|
|
27
|
+
registrar: RuleRegistrar;
|
|
28
|
+
logger: Logger;
|
|
29
|
+
});
|
|
30
|
+
/** Start the periodic health check. No-op if intervalMs is 0. */
|
|
31
|
+
start(): void;
|
|
32
|
+
/** Stop the periodic health check. */
|
|
33
|
+
stop(): void;
|
|
34
|
+
/** Single health check iteration. */
|
|
35
|
+
private check;
|
|
36
|
+
}
|
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Virtual rule registration with jeeves-watcher.
|
|
3
|
+
*
|
|
4
|
+
* Service registers inference rules at startup (with retry) and
|
|
5
|
+
* re-registers opportunistically when watcher restart is detected.
|
|
6
|
+
*
|
|
7
|
+
* @module rules
|
|
8
|
+
*/
|
|
9
|
+
import type { Logger } from 'pino';
|
|
10
|
+
import type { WatcherClient } from '../interfaces/index.js';
|
|
11
|
+
import type { MetaConfig } from '../schema/config.js';
|
|
12
|
+
/**
|
|
13
|
+
* Manages virtual rule registration with watcher.
|
|
14
|
+
*
|
|
15
|
+
* - Registers at startup with exponential retry
|
|
16
|
+
* - Tracks watcher uptime for restart detection
|
|
17
|
+
* - Re-registers opportunistically when uptime decreases
|
|
18
|
+
*/
|
|
19
|
+
export declare class RuleRegistrar {
|
|
20
|
+
private readonly config;
|
|
21
|
+
private readonly logger;
|
|
22
|
+
private readonly watcherClient;
|
|
23
|
+
private lastWatcherUptime;
|
|
24
|
+
private registered;
|
|
25
|
+
constructor(config: MetaConfig, logger: Logger, watcher: WatcherClient);
|
|
26
|
+
/** Whether rules have been successfully registered. */
|
|
27
|
+
get isRegistered(): boolean;
|
|
28
|
+
/**
|
|
29
|
+
* Register rules with watcher. Retries with exponential backoff.
|
|
30
|
+
* Non-blocking — logs errors but never throws.
|
|
31
|
+
*/
|
|
32
|
+
register(): Promise<void>;
|
|
33
|
+
/**
|
|
34
|
+
* Check watcher uptime and re-register if it decreased (restart detected).
|
|
35
|
+
*
|
|
36
|
+
* @param currentUptime - Current watcher uptime in seconds.
|
|
37
|
+
*/
|
|
38
|
+
checkAndReregister(currentUptime: number): Promise<void>;
|
|
39
|
+
}
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Post-registration verification of virtual rule application.
|
|
3
|
+
*
|
|
4
|
+
* After rules are registered with the watcher, verifies that .meta/meta.json
|
|
5
|
+
* files are discoverable via watcher walk (which depends on virtual rules
|
|
6
|
+
* being applied). Logs a warning if expected metas are not found.
|
|
7
|
+
*
|
|
8
|
+
* @module rules/verify
|
|
9
|
+
*/
|
|
10
|
+
import type { WatcherClient } from '../interfaces/index.js';
|
|
11
|
+
import type { MinimalLogger } from '../logger/index.js';
|
|
12
|
+
/**
|
|
13
|
+
* Verify that virtual rules are applied to indexed .meta/meta.json files.
|
|
14
|
+
*
|
|
15
|
+
* Runs a discovery pass and logs the result. If no metas are found but
|
|
16
|
+
* the filesystem likely has some, logs a warning suggesting reindex.
|
|
17
|
+
*
|
|
18
|
+
* @param watcher - WatcherClient for discovery.
|
|
19
|
+
* @param logger - Logger for reporting results.
|
|
20
|
+
* @returns Number of metas discovered.
|
|
21
|
+
*/
|
|
22
|
+
export declare function verifyRuleApplication(watcher: WatcherClient, logger: MinimalLogger): Promise<number>;
|
|
@@ -0,0 +1,66 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Croner-based scheduler that discovers the highest-priority ready phase
|
|
3
|
+
* across the corpus each tick and enqueues it for execution.
|
|
4
|
+
*
|
|
5
|
+
* @module scheduler
|
|
6
|
+
*/
|
|
7
|
+
import type { Logger } from 'pino';
|
|
8
|
+
import type { MetaCache } from '../cache.js';
|
|
9
|
+
import type { SynthesisQueue } from '../queue/index.js';
|
|
10
|
+
import type { RuleRegistrar } from '../rules/index.js';
|
|
11
|
+
import type { ServiceConfig } from '../schema/config.js';
|
|
12
|
+
import type { HttpWatcherClient } from '../watcher-client/index.js';
|
|
13
|
+
/** Result of a scheduler tick's candidate discovery. */
|
|
14
|
+
export interface TickCandidate {
|
|
15
|
+
path: string;
|
|
16
|
+
phase: 'architect' | 'builder' | 'critic';
|
|
17
|
+
band: number;
|
|
18
|
+
}
|
|
19
|
+
/**
|
|
20
|
+
* Periodic scheduler that discovers the highest-priority ready phase
|
|
21
|
+
* across all metas and enqueues it for execution.
|
|
22
|
+
*
|
|
23
|
+
* Supports adaptive backoff when no candidates are found and hot-reloadable
|
|
24
|
+
* cron expressions via {@link Scheduler.updateSchedule}.
|
|
25
|
+
*/
|
|
26
|
+
export declare class Scheduler {
|
|
27
|
+
private job;
|
|
28
|
+
private backoffMultiplier;
|
|
29
|
+
private tickCount;
|
|
30
|
+
private readonly config;
|
|
31
|
+
private readonly queue;
|
|
32
|
+
private readonly logger;
|
|
33
|
+
private readonly watcher;
|
|
34
|
+
private readonly cache;
|
|
35
|
+
private registrar;
|
|
36
|
+
private currentExpression;
|
|
37
|
+
constructor(config: ServiceConfig, queue: SynthesisQueue, logger: Logger, watcher: HttpWatcherClient, cache: MetaCache);
|
|
38
|
+
/** Set the rule registrar for watcher restart detection. */
|
|
39
|
+
setRegistrar(registrar: RuleRegistrar): void;
|
|
40
|
+
/** Start the cron job. */
|
|
41
|
+
start(): void;
|
|
42
|
+
/** Stop the cron job. */
|
|
43
|
+
stop(): void;
|
|
44
|
+
/** Hot-reload the cron schedule expression. */
|
|
45
|
+
updateSchedule(expression: string): void;
|
|
46
|
+
/** Reset backoff multiplier (call after successful phase execution). */
|
|
47
|
+
resetBackoff(): void;
|
|
48
|
+
/** Whether the scheduler is currently running. */
|
|
49
|
+
get isRunning(): boolean;
|
|
50
|
+
/** Next scheduled tick time, or null if not running. */
|
|
51
|
+
get nextRunAt(): Date | null;
|
|
52
|
+
/**
|
|
53
|
+
* Single tick: discover the highest-priority ready phase and enqueue it.
|
|
54
|
+
*
|
|
55
|
+
* Applies adaptive backoff when no candidates are found.
|
|
56
|
+
*/
|
|
57
|
+
private tick;
|
|
58
|
+
/**
|
|
59
|
+
* Discover the highest-priority ready phase across the corpus.
|
|
60
|
+
*
|
|
61
|
+
* Uses phase-state-aware scheduling: priority order is
|
|
62
|
+
* critic (band 1) \> builder (band 2) \> architect (band 3),
|
|
63
|
+
* with weighted staleness as tiebreaker within a band.
|
|
64
|
+
*/
|
|
65
|
+
private discoverNextPhase;
|
|
66
|
+
}
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Scheduling module — staleness detection and candidate selection.
|
|
3
|
+
*
|
|
4
|
+
* @module scheduling
|
|
5
|
+
*/
|
|
6
|
+
export { actualStaleness, computeStalenessScore, hasSteerChanged, isArchitectTriggered, isStale, MAX_STALENESS_SECONDS, } from './staleness.js';
|
|
7
|
+
export { computeEffectiveStaleness, type StalenessCandidate, } from './weightedFormula.js';
|
|
@@ -0,0 +1,68 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Staleness detection via watcher walk.
|
|
3
|
+
*
|
|
4
|
+
* A meta is stale when any watched file in its scope was modified after
|
|
5
|
+
* `_generatedAt`.
|
|
6
|
+
*
|
|
7
|
+
* @module scheduling/staleness
|
|
8
|
+
*/
|
|
9
|
+
import type { WatcherClient } from '../interfaces/index.js';
|
|
10
|
+
import type { MetaJson } from '../schema/index.js';
|
|
11
|
+
/**
|
|
12
|
+
* Check if a meta is stale.
|
|
13
|
+
*
|
|
14
|
+
* Uses watcher `/walk` to enumerate watched files under the scope prefix,
|
|
15
|
+
* then applies a local mtime check (fast) to detect any modifications since
|
|
16
|
+
* `_generatedAt`. Short-circuits on first match.
|
|
17
|
+
*
|
|
18
|
+
* @param scopePrefix - Path prefix for this meta's scope.
|
|
19
|
+
* @param meta - Current meta.json content.
|
|
20
|
+
* @param watcher - WatcherClient instance.
|
|
21
|
+
* @returns True if any file in scope was modified after `_generatedAt`.
|
|
22
|
+
*/
|
|
23
|
+
export declare function isStale(scopePrefix: string, meta: MetaJson, watcher: WatcherClient): Promise<boolean>;
|
|
24
|
+
/** Maximum staleness for never-synthesized metas (1 year in seconds). */
|
|
25
|
+
export declare const MAX_STALENESS_SECONDS: number;
|
|
26
|
+
/**
|
|
27
|
+
* Compute actual staleness in seconds (now minus _generatedAt).
|
|
28
|
+
*
|
|
29
|
+
* Never-synthesized metas are capped at {@link MAX_STALENESS_SECONDS}
|
|
30
|
+
* (1 year) so that depth weighting can differentiate them. Without
|
|
31
|
+
* bounding, `Infinity * depthFactor` = `Infinity` for all depths.
|
|
32
|
+
*
|
|
33
|
+
* @param meta - Current meta.json content.
|
|
34
|
+
* @returns Staleness in seconds, capped at 1 year for never-synthesized metas.
|
|
35
|
+
*/
|
|
36
|
+
export declare function actualStaleness(meta: MetaJson): number;
|
|
37
|
+
/**
|
|
38
|
+
* Check whether the architect step should be triggered.
|
|
39
|
+
*
|
|
40
|
+
* @param meta - Current meta.json.
|
|
41
|
+
* @param structureChanged - Whether the structure hash changed.
|
|
42
|
+
* @param steerChanged - Whether the steer directive changed.
|
|
43
|
+
* @param architectEvery - Config: run architect every N cycles.
|
|
44
|
+
* @returns True if the architect step should run.
|
|
45
|
+
*/
|
|
46
|
+
export declare function isArchitectTriggered(meta: MetaJson, structureChanged: boolean, steerChanged: boolean, architectEvery: number): boolean;
|
|
47
|
+
/**
|
|
48
|
+
* Detect whether the steer directive changed since the last archive.
|
|
49
|
+
*
|
|
50
|
+
* @param currentSteer - Current _steer value (or undefined).
|
|
51
|
+
* @param archiveSteer - Archive _steer value (or undefined).
|
|
52
|
+
* @param hasArchive - Whether an archive snapshot exists.
|
|
53
|
+
* @returns True if steer changed.
|
|
54
|
+
*/
|
|
55
|
+
export declare function hasSteerChanged(currentSteer: string | undefined, archiveSteer: string | undefined, hasArchive: boolean): boolean;
|
|
56
|
+
/**
|
|
57
|
+
* Compute a normalized staleness score (0–1) for display purposes.
|
|
58
|
+
*
|
|
59
|
+
* Uses the same depth/emphasis weighting as candidate selection,
|
|
60
|
+
* normalized to a 30-day window.
|
|
61
|
+
*
|
|
62
|
+
* @param stalenessSeconds - Raw staleness in seconds (null = never synthesized).
|
|
63
|
+
* @param depth - Meta tree depth.
|
|
64
|
+
* @param emphasis - Scheduling emphasis multiplier.
|
|
65
|
+
* @param depthWeight - Depth weighting exponent from config.
|
|
66
|
+
* @returns Normalized score between 0 and 1.
|
|
67
|
+
*/
|
|
68
|
+
export declare function computeStalenessScore(stalenessSeconds: number | null, depth: number, emphasis: number, depthWeight: number): number;
|
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Weighted staleness formula for candidate selection.
|
|
3
|
+
*
|
|
4
|
+
* effectiveStaleness = actualStaleness * (normalizedDepth + 1) ^ (depthWeight * emphasis)
|
|
5
|
+
*
|
|
6
|
+
* @module scheduling/weightedFormula
|
|
7
|
+
*/
|
|
8
|
+
import type { MetaNode } from '../discovery/index.js';
|
|
9
|
+
import type { MetaJson } from '../schema/index.js';
|
|
10
|
+
/** A candidate meta with computed staleness. */
|
|
11
|
+
export interface StalenessCandidate {
|
|
12
|
+
/** The meta node. */
|
|
13
|
+
node: MetaNode;
|
|
14
|
+
/** Current meta.json content. */
|
|
15
|
+
meta: MetaJson;
|
|
16
|
+
/** Actual staleness in seconds. */
|
|
17
|
+
actualStaleness: number;
|
|
18
|
+
/** Effective staleness after depth weighting. */
|
|
19
|
+
effectiveStaleness: number;
|
|
20
|
+
}
|
|
21
|
+
/**
|
|
22
|
+
* Compute effective staleness for a set of candidates.
|
|
23
|
+
*
|
|
24
|
+
* Normalizes depths so the minimum becomes 0, then applies the formula:
|
|
25
|
+
* effectiveStaleness = actualStaleness * (normalizedDepth + 1) ^ (depthWeight * emphasis)
|
|
26
|
+
*
|
|
27
|
+
* Per-meta _emphasis (default 1) multiplies depthWeight, allowing individual
|
|
28
|
+
* metas to tune how much their tree position affects scheduling.
|
|
29
|
+
*
|
|
30
|
+
* @param candidates - Array of \{ node, meta, actualStaleness \}.
|
|
31
|
+
* @param depthWeight - Exponent for depth weighting (0 = pure staleness).
|
|
32
|
+
* @returns Same array with effectiveStaleness computed.
|
|
33
|
+
*/
|
|
34
|
+
export declare function computeEffectiveStaleness(candidates: Array<{
|
|
35
|
+
node: MetaNode;
|
|
36
|
+
meta: MetaJson;
|
|
37
|
+
actualStaleness: number;
|
|
38
|
+
}>, depthWeight: number): StalenessCandidate[];
|