@iworkforces/tracelattice 2.1.2 → 2.2.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +45 -10
- package/dist/ServerConfig.d.ts +9 -5
- package/dist/ServerConfig.d.ts.map +1 -1
- package/dist/ServerConfig.js.map +1 -1
- package/dist/config/ConfigLoader.d.ts +20 -7
- package/dist/config/ConfigLoader.d.ts.map +1 -1
- package/dist/config/ConfigLoader.js.map +1 -1
- package/dist/contracts/PersistenceBackend.d.ts +10 -1
- package/dist/contracts/PersistenceBackend.d.ts.map +1 -1
- package/dist/contracts/calibrator.d.ts +9 -6
- package/dist/contracts/calibrator.d.ts.map +1 -1
- package/dist/contracts/interfaces.d.ts +6 -0
- package/dist/contracts/interfaces.d.ts.map +1 -1
- package/dist/contracts/persistence-work.d.ts +13 -1
- package/dist/contracts/persistence-work.d.ts.map +1 -1
- package/dist/contracts/strategy.d.ts +14 -9
- package/dist/contracts/strategy.d.ts.map +1 -1
- package/dist/core/DurableThoughtIdentityIndex.d.ts +35 -0
- package/dist/core/DurableThoughtIdentityIndex.d.ts.map +1 -0
- package/dist/core/DurableThoughtIdentityIndex.js +94 -0
- package/dist/core/DurableThoughtIdentityIndex.js.map +1 -0
- package/dist/core/HistoryManager.d.ts +5 -0
- package/dist/core/HistoryManager.d.ts.map +1 -1
- package/dist/core/HistoryManager.js +37 -4
- package/dist/core/HistoryManager.js.map +1 -1
- package/dist/core/IHistoryManager.d.ts +2 -0
- package/dist/core/IHistoryManager.d.ts.map +1 -1
- package/dist/core/PersistenceBuffer.d.ts +7 -1
- package/dist/core/PersistenceBuffer.d.ts.map +1 -1
- package/dist/core/PersistenceBuffer.js +13 -1
- package/dist/core/PersistenceBuffer.js.map +1 -1
- package/dist/core/PersistenceRestore.d.ts.map +1 -1
- package/dist/core/PersistenceRestore.js +11 -3
- package/dist/core/PersistenceRestore.js.map +1 -1
- package/dist/core/PersistenceWorkQueue.d.ts +13 -1
- package/dist/core/PersistenceWorkQueue.d.ts.map +1 -1
- package/dist/core/PersistenceWorkQueue.js +86 -11
- package/dist/core/PersistenceWorkQueue.js.map +1 -1
- package/dist/core/PersistenceWriter.d.ts.map +1 -1
- package/dist/core/PersistenceWriter.js +3 -0
- package/dist/core/PersistenceWriter.js.map +1 -1
- package/dist/core/ThoughtEvaluator.d.ts +7 -4
- package/dist/core/ThoughtEvaluator.d.ts.map +1 -1
- package/dist/core/ThoughtEvaluator.js +15 -7
- package/dist/core/ThoughtEvaluator.js.map +1 -1
- package/dist/core/ThoughtProcessor.d.ts.map +1 -1
- package/dist/core/ThoughtProcessor.js +19 -7
- package/dist/core/ThoughtProcessor.js.map +1 -1
- package/dist/core/ThoughtReferenceIndex.d.ts +4 -0
- package/dist/core/ThoughtReferenceIndex.d.ts.map +1 -1
- package/dist/core/ThoughtReferenceIndex.js +28 -1
- package/dist/core/ThoughtReferenceIndex.js.map +1 -1
- package/dist/core/VerificationOutcomeAdmission.d.ts +8 -1
- package/dist/core/VerificationOutcomeAdmission.d.ts.map +1 -1
- package/dist/core/VerificationOutcomeAdmission.js.map +1 -1
- package/dist/core/VerificationTargetRestore.d.ts +5 -0
- package/dist/core/VerificationTargetRestore.d.ts.map +1 -0
- package/dist/core/VerificationTargetRestore.js +61 -0
- package/dist/core/VerificationTargetRestore.js.map +1 -0
- package/dist/core/evaluator/Aggregator.d.ts +2 -1
- package/dist/core/evaluator/Aggregator.d.ts.map +1 -1
- package/dist/core/evaluator/Aggregator.js +4 -12
- package/dist/core/evaluator/Aggregator.js.map +1 -1
- package/dist/core/evaluator/Calibrator.d.ts +13 -9
- package/dist/core/evaluator/Calibrator.d.ts.map +1 -1
- package/dist/core/evaluator/Calibrator.js +25 -11
- package/dist/core/evaluator/Calibrator.js.map +1 -1
- package/dist/core/evaluator/PatternDetector.d.ts +2 -1
- package/dist/core/evaluator/PatternDetector.d.ts.map +1 -1
- package/dist/core/evaluator/PatternDetector.js +13 -12
- package/dist/core/evaluator/PatternDetector.js.map +1 -1
- package/dist/core/evaluator/SignalComputer.d.ts +3 -2
- package/dist/core/evaluator/SignalComputer.d.ts.map +1 -1
- package/dist/core/evaluator/SignalComputer.js +4 -9
- package/dist/core/evaluator/SignalComputer.js.map +1 -1
- package/dist/core/evaluator/VerificationLinks.d.ts +19 -0
- package/dist/core/evaluator/VerificationLinks.d.ts.map +1 -0
- package/dist/core/evaluator/VerificationLinks.js +113 -0
- package/dist/core/evaluator/VerificationLinks.js.map +1 -0
- package/dist/core/evaluator/calibration-math.d.ts +12 -2
- package/dist/core/evaluator/calibration-math.d.ts.map +1 -1
- package/dist/core/evaluator/calibration-math.js +11 -2
- package/dist/core/evaluator/calibration-math.js.map +1 -1
- package/dist/core/graph/EdgeEmitter.d.ts.map +1 -1
- package/dist/core/graph/EdgeEmitter.js +2 -1
- package/dist/core/graph/EdgeEmitter.js.map +1 -1
- package/dist/core/graph/GraphView.d.ts +5 -5
- package/dist/core/graph/GraphView.d.ts.map +1 -1
- package/dist/core/graph/GraphView.js +11 -11
- package/dist/core/graph/GraphView.js.map +1 -1
- package/dist/core/reasoning/ActiveEvidenceProjection.d.ts +20 -0
- package/dist/core/reasoning/ActiveEvidenceProjection.d.ts.map +1 -0
- package/dist/core/reasoning/ActiveEvidenceProjection.js +100 -0
- package/dist/core/reasoning/ActiveEvidenceProjection.js.map +1 -0
- package/dist/core/reasoning/strategies/TreeOfThoughtStrategy.d.ts +5 -4
- package/dist/core/reasoning/strategies/TreeOfThoughtStrategy.d.ts.map +1 -1
- package/dist/core/reasoning/strategies/TreeOfThoughtStrategy.js +24 -14
- package/dist/core/reasoning/strategies/TreeOfThoughtStrategy.js.map +1 -1
- package/dist/lib.d.ts.map +1 -1
- package/dist/lib.js +3 -1
- package/dist/lib.js.map +1 -1
- package/dist/metrics/metrics.impl.d.ts.map +1 -1
- package/dist/metrics/metrics.impl.js +19 -7
- package/dist/metrics/metrics.impl.js.map +1 -1
- package/dist/persistence/BacktrackPersistence.d.ts +13 -0
- package/dist/persistence/BacktrackPersistence.d.ts.map +1 -0
- package/dist/persistence/BacktrackPersistence.js +90 -0
- package/dist/persistence/BacktrackPersistence.js.map +1 -0
- package/dist/persistence/FilePersistence.d.ts +2 -1
- package/dist/persistence/FilePersistence.d.ts.map +1 -1
- package/dist/persistence/FilePersistence.js +28 -0
- package/dist/persistence/FilePersistence.js.map +1 -1
- package/dist/persistence/FileSnapshotV2.d.ts +2 -0
- package/dist/persistence/FileSnapshotV2.d.ts.map +1 -1
- package/dist/persistence/FileSnapshotV2.js +6 -2
- package/dist/persistence/FileSnapshotV2.js.map +1 -1
- package/dist/persistence/MemoryPersistence.d.ts +2 -1
- package/dist/persistence/MemoryPersistence.d.ts.map +1 -1
- package/dist/persistence/MemoryPersistence.js +21 -1
- package/dist/persistence/MemoryPersistence.js.map +1 -1
- package/dist/persistence/PersistenceCodec.d.ts.map +1 -1
- package/dist/persistence/PersistenceCodec.js +5 -0
- package/dist/persistence/PersistenceCodec.js.map +1 -1
- package/dist/persistence/PersistenceErrors.d.ts +1 -1
- package/dist/persistence/PersistenceErrors.d.ts.map +1 -1
- package/dist/persistence/PersistenceErrors.js.map +1 -1
- package/dist/persistence/PersistenceScope.d.ts +1 -1
- package/dist/persistence/PersistenceScope.d.ts.map +1 -1
- package/dist/persistence/PersistenceScope.js.map +1 -1
- package/dist/persistence/SqlitePersistence.d.ts +2 -1
- package/dist/persistence/SqlitePersistence.d.ts.map +1 -1
- package/dist/persistence/SqlitePersistence.js +18 -0
- package/dist/persistence/SqlitePersistence.js.map +1 -1
- package/package.json +12 -11
package/README.md
CHANGED
|
@@ -10,7 +10,7 @@ An MCP server that gives AI agents structured sequential thinking with tool and
|
|
|
10
10
|
- DAG-based thought graph with 8 edge kinds (sequence, branch, merge, verifies, critiques, derives_from, tool_invocation, revises) and topological traversal
|
|
11
11
|
- Pluggable reasoning strategies. Sequential by default, or Tree-of-Thought with BFS/beam search and plateau detection
|
|
12
12
|
- Tool interleave: suspend a thinking chain, run a tool call, then resume where you left off
|
|
13
|
-
- Confidence calibration
|
|
13
|
+
- Confidence calibration with raw-prior shrinkage, plus Brier score and Expected Calibration Error (ECE) for recorded raw predictions
|
|
14
14
|
- Branch compression: cold branches get rolled into summaries automatically, with a sliding-window dehydration policy
|
|
15
15
|
- Outcome recording for tool_call/tool_observation results with metadata
|
|
16
16
|
- Tool and skill recommendations with confidence scores, rationales, and automatic discovery
|
|
@@ -110,7 +110,9 @@ Set `TRACELATTICE_LOG_LEVEL` in the process environment to `debug`, `info`, `war
|
|
|
110
110
|
TRACELATTICE_LOG_LEVEL=debug tracelattice
|
|
111
111
|
```
|
|
112
112
|
|
|
113
|
-
|
|
113
|
+
Supported environment variables override values from configuration files. The defaults below describe
|
|
114
|
+
`ServerConfig` when no file or environment override is present; `.example.env` contains explicit example
|
|
115
|
+
overrides, not another set of defaults.
|
|
114
116
|
|
|
115
117
|
| Variable | Default | Description |
|
|
116
118
|
| --------------------------------------- | ------------ | ------------------------------------------- |
|
|
@@ -119,14 +121,14 @@ Environment variables override values from configuration files.
|
|
|
119
121
|
| `TRACELATTICE_MAX_BRANCHES` | `50` | Maximum number of branches |
|
|
120
122
|
| `TRACELATTICE_MAX_BRANCH_SIZE` | `100` | Maximum size of each branch |
|
|
121
123
|
| `TRACELATTICE_LOG_LEVEL` | `info` | Log level: `debug`, `info`, `warn`, `error` |
|
|
122
|
-
| `TRACELATTICE_PRETTY_LOG` | `true` |
|
|
124
|
+
| `TRACELATTICE_PRETTY_LOG` | `true` | Only the literal `false` disables pretty logging; other values do not override a file setting |
|
|
123
125
|
| `TRACELATTICE_SESSION_MAX_PER_OWNER` | `50` | Maximum isolated sessions per owner |
|
|
124
126
|
| `TRACELATTICE_TOOL_INTERLEAVE_TTL_MS` | `60000` | Suspended tool-call token TTL in ms |
|
|
125
127
|
| `TRACELATTICE_TOOL_INTERLEAVE_SWEEP_MS` | `60000` | Expired suspension cleanup interval in ms |
|
|
126
128
|
|
|
127
129
|
### Config files
|
|
128
130
|
|
|
129
|
-
Configuration files are loaded from the first
|
|
131
|
+
Configuration files are loaded from the first valid path in this order: an explicit `ConfigLoader` path or `TRACELATTICE_CONFIG` replaces the search list; otherwise `.claude/config.json`, `.claude/config.yaml`, `.claude/config.yml`, then the same filenames under `~/.claude/`. An invalid file is logged and the next candidate is tried. With no valid file, the loader applies environment overrides to an empty object; `ServerConfig` supplies defaults. Only supported environment variables override file values. Logging (`logLevel` and `prettyLog`) is read from the loaded file/environment configuration separately from `ServerConfig`.
|
|
130
132
|
|
|
131
133
|
```yaml
|
|
132
134
|
maxHistorySize: 10000
|
|
@@ -135,8 +137,10 @@ maxBranchSize: 100
|
|
|
135
137
|
skillDirs:
|
|
136
138
|
- .claude/skills
|
|
137
139
|
- ~/.claude/skills
|
|
140
|
+
- .agents/skills
|
|
141
|
+
- ~/.agents/skills
|
|
138
142
|
discoveryCache:
|
|
139
|
-
ttl: 300000
|
|
143
|
+
ttl: 42000 # example override in milliseconds; default 300000, env TTL is seconds
|
|
140
144
|
maxSize: 100
|
|
141
145
|
persistence:
|
|
142
146
|
enabled: false
|
|
@@ -144,6 +148,9 @@ persistence:
|
|
|
144
148
|
options:
|
|
145
149
|
dataDir: ./.tracelattice
|
|
146
150
|
dbPath: ./.tracelattice/history.db
|
|
151
|
+
persistenceBufferSize: 7 # example file-only override; default 100
|
|
152
|
+
persistenceFlushInterval: 750 # milliseconds, file-only; default 1000
|
|
153
|
+
persistenceMaxRetries: 2 # example file-only override; default 3
|
|
147
154
|
features:
|
|
148
155
|
dagEdges: true
|
|
149
156
|
reasoningStrategy: sequential # sequential or tot
|
|
@@ -152,8 +159,8 @@ features:
|
|
|
152
159
|
toolInterleave: true
|
|
153
160
|
newThoughtTypes: true
|
|
154
161
|
outcomeRecording: true
|
|
155
|
-
toolInterleaveTtlMs: 60000
|
|
156
|
-
toolInterleaveSweepMs: 60000
|
|
162
|
+
toolInterleaveTtlMs: 45000 # example override in milliseconds; default 60000
|
|
163
|
+
toolInterleaveSweepMs: 55000 # example override in milliseconds; default 60000
|
|
157
164
|
maxSessionsPerOwner: 50
|
|
158
165
|
```
|
|
159
166
|
|
|
@@ -164,7 +171,7 @@ All feature flags default to enabled in `ServerConfig`. Set a boolean flag to `f
|
|
|
164
171
|
| Variable | Description |
|
|
165
172
|
| ------------------------------------------ | ------------------------------------------------------------------------ |
|
|
166
173
|
| `TRACELATTICE_FEATURES_DAG_EDGES` | Enable DAG edges for thought relationships |
|
|
167
|
-
| `TRACELATTICE_FEATURES_CALIBRATION` | Enable confidence calibration
|
|
174
|
+
| `TRACELATTICE_FEATURES_CALIBRATION` | Enable raw-prior confidence calibration |
|
|
168
175
|
| `TRACELATTICE_FEATURES_COMPRESSION` | Enable branch compression for cold branches |
|
|
169
176
|
| `TRACELATTICE_FEATURES_TOOL_INTERLEAVE` | Enable suspend/resume for tool calls |
|
|
170
177
|
| `TRACELATTICE_FEATURES_NEW_THOUGHT_TYPES` | Enable tool_call, tool_observation, assumption, decomposition, backtrack |
|
|
@@ -187,12 +194,24 @@ All feature flags default to enabled in `ServerConfig`. Set a boolean flag to `f
|
|
|
187
194
|
|
|
188
195
|
| Variable | Default | Description |
|
|
189
196
|
| --------------------------------------- | -------------------------------------- | ------------------------------------------------------- |
|
|
190
|
-
| `TRACELATTICE_SKILL_DIRS` | `.claude/skills:<home>/.claude/skills` | Colon-separated skill directories
|
|
197
|
+
| `TRACELATTICE_SKILL_DIRS` | `.claude/skills:<home>/.claude/skills:.agents/skills:<home>/.agents/skills` | Colon-separated skill directories |
|
|
191
198
|
| `TRACELATTICE_TOOL_DIRS` | `.claude/tools:<home>/.claude/tools` | Colon-separated tool directories |
|
|
192
199
|
| `TRACELATTICE_DISCOVERY_CACHE_TTL` | `300` | Discovery cache TTL in seconds; stored internally as ms |
|
|
193
200
|
| `TRACELATTICE_DISCOVERY_CACHE_MAX_SIZE` | `100` | Discovery cache max entries |
|
|
194
201
|
| `TRACELATTICE_WATCHER_VERBOSE` | unset | Log skill watcher events when set to `true` |
|
|
195
202
|
|
|
203
|
+
The default skill paths include project-local `.claude/skills` and `.agents/skills` plus both paths
|
|
204
|
+
under the user's home directory. The default tool paths include only `.claude/tools` and its home
|
|
205
|
+
directory counterpart. Setting either root variable replaces its entire default list; `~` in an
|
|
206
|
+
environment value is not expanded by `ConfigLoader`. `TRACELATTICE_DISCOVERY_CACHE_TTL=300` means
|
|
207
|
+
300 seconds and becomes `discoveryCache.ttl: 300000` milliseconds. The interleave environment
|
|
208
|
+
variables ending in `_MS` and the corresponding YAML fields use milliseconds.
|
|
209
|
+
|
|
210
|
+
`persistenceBufferSize` (default 100 thoughts), `persistenceFlushInterval` (default 1000 ms), and
|
|
211
|
+
`persistenceMaxRetries` (default 3) are YAML/JSON settings, not environment variables. There are no
|
|
212
|
+
`TRACELATTICE_PERSISTENCE_BUFFER_SIZE`, `TRACELATTICE_PERSISTENCE_FLUSH_INTERVAL`, or
|
|
213
|
+
`TRACELATTICE_PERSISTENCE_MAX_RETRIES` overrides.
|
|
214
|
+
|
|
196
215
|
## Transports
|
|
197
216
|
|
|
198
217
|
Set `TRACELATTICE_TRANSPORT_TYPE` to pick one:
|
|
@@ -254,7 +273,23 @@ TraceLattice exposes only the current API and persistence contract. There are no
|
|
|
254
273
|
| Partial server cleanup | Await `dispose()` to release the server and all container-owned resources |
|
|
255
274
|
| Unprefixed environment variables | The `TRACELATTICE_*` variables documented above |
|
|
256
275
|
|
|
257
|
-
File persistence accepts the strict v2 `snapshot.json` document. SQLite persistence accepts the exact v2 schema with its authoritative `schema_version` row. Invalid, unknown, or differently versioned storage fails closed; startup does not rewrite it.
|
|
276
|
+
File persistence accepts the strict v2 `snapshot.json` document. SQLite persistence accepts the exact v2 schema with its authoritative `schema_version` row. Invalid, unknown, or differently versioned storage fails closed; startup does not rewrite it. Backtrack support did not change File or SQLite from v2 and requires no migration or version bump.
|
|
277
|
+
|
|
278
|
+
## Precision behavior
|
|
279
|
+
|
|
280
|
+
### Calibration and evaluation limits
|
|
281
|
+
|
|
282
|
+
Calibration blends a raw confidence with the empirical outcome mean for its thought type. For `n` recorded outcomes of that type, `priorWeight = 10 / (10 + n)` and the blended value is `priorWeight * raw + (1 - priorWeight) * perTypeMean`. With no outcomes for a type, the empirical component has zero weight and calibration returns the raw confidence exactly.
|
|
283
|
+
|
|
284
|
+
Temperature fitting begins at 10 outcomes. It uses per-type leave-one-out blends, the fixed grid `[0.5, 0.75, 1, 1.25, 1.5, 2]`, and deterministic ties that retain `1` before grid order. Temperature is applied after the blend. Brier and ECE reported by `Calibrator.metrics()` always score the stored raw predictions and outcomes, not transformed holdout outputs.
|
|
285
|
+
|
|
286
|
+
The checked evaluation report separates deterministic structural validation and controlled raw and calibrated probability metrics. `natural_language_accuracy` is unmeasured. These checks do not judge factuality, guarantee better calibration, or promise that every individual confidence changes in one direction.
|
|
287
|
+
|
|
288
|
+
### Persistence, recovery, and backtracking
|
|
289
|
+
|
|
290
|
+
`PersistenceBackend` requires `saveBacktrackForSession(sessionId, thought, targetThoughtId)`. Every custom backend must implement it. The operation atomically corrects every retained stable-ID copy of the target, appends the backtrack thought, and applies retention. There is no capability fallback; the ordinary persistence methods retain their existing contracts.
|
|
291
|
+
|
|
292
|
+
Restore reads retained records only. It repairs retained backtrack copies without writing the snapshot, ignores an absent retained target, and rejects an ambiguous retained numeric target. Evidence already pruned by retention or eviction cannot be recovered.
|
|
258
293
|
|
|
259
294
|
## Development
|
|
260
295
|
|
package/dist/ServerConfig.d.ts
CHANGED
|
@@ -28,7 +28,7 @@ import type { FeatureFlags } from './contracts/features.js';
|
|
|
28
28
|
export interface ServerConfigOptions {
|
|
29
29
|
/**
|
|
30
30
|
* Maximum number of thoughts to keep in history.
|
|
31
|
-
* @default
|
|
31
|
+
* @default 10000
|
|
32
32
|
*/
|
|
33
33
|
maxHistorySize?: number;
|
|
34
34
|
/**
|
|
@@ -43,7 +43,7 @@ export interface ServerConfigOptions {
|
|
|
43
43
|
maxBranchSize?: number;
|
|
44
44
|
/**
|
|
45
45
|
* Directory paths to search for skills.
|
|
46
|
-
* @default
|
|
46
|
+
* @default Project .claude/skills and .agents/skills, plus both paths under the home directory
|
|
47
47
|
*/
|
|
48
48
|
skillDirs?: string[];
|
|
49
49
|
/**
|
|
@@ -72,16 +72,19 @@ export interface ServerConfigOptions {
|
|
|
72
72
|
persistence?: PersistenceConfig;
|
|
73
73
|
/**
|
|
74
74
|
* Maximum number of thoughts to buffer before flushing to persistence.
|
|
75
|
+
* YAML/JSON only; no environment override.
|
|
75
76
|
* @default 100
|
|
76
77
|
*/
|
|
77
78
|
persistenceBufferSize?: number;
|
|
78
79
|
/**
|
|
79
80
|
* Interval in milliseconds between periodic persistence flushes.
|
|
81
|
+
* YAML/JSON only; no environment override.
|
|
80
82
|
* @default 1000
|
|
81
83
|
*/
|
|
82
84
|
persistenceFlushInterval?: number;
|
|
83
85
|
/**
|
|
84
86
|
* Maximum number of retries for failed persistence flushes.
|
|
87
|
+
* YAML/JSON only; no environment override.
|
|
85
88
|
* @default 3
|
|
86
89
|
*/
|
|
87
90
|
persistenceMaxRetries?: number;
|
|
@@ -115,7 +118,8 @@ export interface ServerConfigOptions {
|
|
|
115
118
|
*
|
|
116
119
|
* @remarks
|
|
117
120
|
* - Values outside recommended ranges trigger warnings but are still applied
|
|
118
|
-
* -
|
|
121
|
+
* - Supported environment variables override file-based configuration through ConfigLoader
|
|
122
|
+
* - Logging uses file/environment input separately; ServerConfig does not hold log settings
|
|
119
123
|
* - The `toJSON()` method provides a plain object representation
|
|
120
124
|
*
|
|
121
125
|
* @example
|
|
@@ -186,7 +190,7 @@ export declare class ServerConfig {
|
|
|
186
190
|
/**
|
|
187
191
|
* Validates the max history size value.
|
|
188
192
|
* @param value - The value to validate
|
|
189
|
-
* @returns The validated value or default (
|
|
193
|
+
* @returns The validated value or default (10000)
|
|
190
194
|
* @private
|
|
191
195
|
*/
|
|
192
196
|
private validateMaxHistorySize;
|
|
@@ -207,7 +211,7 @@ export declare class ServerConfig {
|
|
|
207
211
|
/**
|
|
208
212
|
* Validates the skill directories value.
|
|
209
213
|
* @param value - The value to validate
|
|
210
|
-
* @returns The validated value or
|
|
214
|
+
* @returns The validated value or project-local and home-directory .claude/.agents skill paths
|
|
211
215
|
* @private
|
|
212
216
|
*/
|
|
213
217
|
private validateSkillDirs;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"ServerConfig.d.ts","sourceRoot":"","sources":["../src/ServerConfig.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG;AAKH,OAAO,KAAK,EAAE,iBAAiB,EAAE,MAAM,mCAAmC,CAAC;AAE3E;;;;;;;;;;;;;;;GAeG;AAEH,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,yBAAyB,CAAC;AAC5D,MAAM,WAAW,mBAAmB;IACnC;;;OAGG;IACH,cAAc,CAAC,EAAE,MAAM,CAAC;IAExB;;;OAGG;IACH,WAAW,CAAC,EAAE,MAAM,CAAC;IAErB;;;OAGG;IACH,aAAa,CAAC,EAAE,MAAM,CAAC;IAEvB;;;OAGG;IACH,SAAS,CAAC,EAAE,MAAM,EAAE,CAAC;IAErB;;;OAGG;IACH,QAAQ,CAAC,EAAE,MAAM,EAAE,CAAC;IAEpB;;OAEG;IACH,cAAc,CAAC,EAAE;QAChB;;;WAGG;QACH,GAAG,CAAC,EAAE,MAAM,CAAC;QACb;;;WAGG;QACH,OAAO,CAAC,EAAE,MAAM,CAAC;KACjB,CAAC;IAEF;;OAEG;IACH,WAAW,CAAC,EAAE,iBAAiB,CAAC;IAEhC
|
|
1
|
+
{"version":3,"file":"ServerConfig.d.ts","sourceRoot":"","sources":["../src/ServerConfig.ts"],"names":[],"mappings":"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"}
|
package/dist/ServerConfig.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"ServerConfig.js","sources":["../src/ServerConfig.ts"],"sourcesContent":["/**\n * Server configuration management with validation.\n *\n * This module provides the `ServerConfig` class which handles all server configuration\n * with built-in validation and sensible defaults. Configuration values are validated\n * on construction and warnings are emitted for out-of-range values.\n *\n * @module ServerConfig\n */\n\nimport { homedir } from 'node:os';\nimport { join } from 'node:path';\nimport { ConfigurationError } from './errors.js';\nimport type { PersistenceConfig } from './contracts/PersistenceBackend.js';\n\n/**\n * Configuration options for creating a `ServerConfig` instance.\n *\n * All properties are optional with sensible defaults applied during validation.\n *\n * @example\n * ```typescript\n * const options: ServerConfigOptions = {\n * maxHistorySize: 500,\n * maxBranches: 25,\n * skillDirs: ['./custom-skills'],\n * toolDirs: ['./custom-tools'],\n * persistence: { enabled: true, backend: 'sqlite' }\n * };\n * ```\n */\n\nimport type { FeatureFlags } from './contracts/features.js';\nexport interface ServerConfigOptions {\n\t/**\n\t * Maximum number of thoughts to keep in history.\n\t * @default 1000\n\t */\n\tmaxHistorySize?: number;\n\n\t/**\n\t * Maximum number of branches to maintain.\n\t * @default 50\n\t */\n\tmaxBranches?: number;\n\n\t/**\n\t * Maximum size of each branch.\n\t * @default 100\n\t */\n\tmaxBranchSize?: number;\n\n\t/**\n\t * Directory paths to search for skills.\n\t * @default ['.claude/skills', '~/.claude/skills', '.agents/skills', '~/.agents/skills']\n\t */\n\tskillDirs?: string[];\n\n\t/**\n\t * Directory paths to search for tools.\n\t * @default ['.claude/tools', '~/.claude/tools']\n\t */\n\ttoolDirs?: string[];\n\n\t/**\n\t * Discovery cache configuration.\n\t */\n\tdiscoveryCache?: {\n\t\t/**\n\t\t * Time-to-live for cache entries in milliseconds.\n\t\t * @default 300000 (5 minutes)\n\t\t */\n\t\tttl?: number;\n\t\t/**\n\t\t * Maximum number of entries in the cache.\n\t\t * @default 100\n\t\t */\n\t\tmaxSize?: number;\n\t};\n\n\t/**\n\t * Persistence configuration for storing history and state.\n\t */\n\tpersistence?: PersistenceConfig;\n\n\t/**\n\t * Maximum number of thoughts to buffer before flushing to persistence.\n\t * @default 100\n\t */\n\tpersistenceBufferSize?: number;\n\n\t/**\n\t * Interval in milliseconds between periodic persistence flushes.\n\t * @default 1000\n\t */\n\tpersistenceFlushInterval?: number;\n\n\t/**\n\t * Maximum number of retries for failed persistence flushes.\n\t * @default 3\n\t */\n\tpersistenceMaxRetries?: number;\n\n\t/**\n\t * Feature flag overrides. Missing fields are filled with defaults (all ON,\n\t * reasoningStrategy='sequential').\n\t */\n\tfeatures?: Partial<FeatureFlags>;\n\n\t/**\n\t * TTL in milliseconds for suspended tool-interleave entries in SuspensionStore.\n\t * @default 60000\n\t */\n\ttoolInterleaveTtlMs?: number;\n\n\t/**\n\t * Sweep interval in milliseconds for SuspensionStore expiration cleanup.\n\t * @default 60000\n\t */\n\ttoolInterleaveSweepMs?: number;\n\n\t/**\n\t * Maximum sessions per owner. Prevents one user from consuming all session slots.\n\t * @default 50\n\t */\n\tmaxSessionsPerOwner?: number;\n}\n\n/**\n * Server configuration with validation and defaults.\n *\n * This class manages all server configuration including history limits,\n * branch limits, discovery directories, cache settings, and persistence.\n * All values are validated on construction with appropriate defaults applied.\n *\n * @remarks\n * - Values outside recommended ranges trigger warnings but are still applied\n * - Environment variables override file-based configuration\n * - The `toJSON()` method provides a plain object representation\n *\n * @example\n * ```typescript\n * // Using defaults\n * const config1 = new ServerConfig();\n * console.log(config1.maxHistorySize); // 10000\n *\n * // With custom options\n * const config2 = new ServerConfig({\n * maxHistorySize: 500,\n * persistence: { enabled: true, backend: 'file', options: { dataDir: './data' } }\n * });\n *\n * // Export as plain object\n * const json = config2.toJSON();\n * ```\n */\nexport class ServerConfig {\n\t/** Maximum number of thoughts to keep in history. */\n\tpublic maxHistorySize: number;\n\n\t/** Maximum number of branches to maintain. */\n\tpublic maxBranches: number;\n\n\t/** Maximum size of each branch. */\n\tpublic maxBranchSize: number;\n\n\t/** Directory paths to search for skills. */\n\tpublic skillDirs: string[];\n\n\t/** Directory paths to search for tools. */\n\tpublic toolDirs: string[];\n\n\t/** Discovery cache configuration. */\n\tpublic discoveryCache: { ttl: number; maxSize: number };\n\n\t/** Persistence configuration. */\n\tpublic persistence: PersistenceConfig;\n\n\t/** Maximum number of thoughts to buffer before flushing to persistence. */\n\tpublic persistenceBufferSize: number;\n\n\t/** Interval in milliseconds between periodic persistence flushes. */\n\tpublic persistenceFlushInterval: number;\n\n\t/** Maximum number of retries for failed persistence flushes. */\n\tpublic persistenceMaxRetries: number;\n\n\t/** Feature flag toggles. */\n\tpublic features: FeatureFlags;\n\n\t/** TTL in milliseconds for suspended tool-interleave entries. */\n\tpublic toolInterleaveTtlMs: number;\n\n\t/** Sweep interval in milliseconds for SuspensionStore expiration cleanup. */\n\tpublic toolInterleaveSweepMs: number;\n\n\t/** Maximum sessions per owner (LRU per-owner bucket). */\n\tpublic maxSessionsPerOwner: number;\n\n\t/**\n\t * Creates a new ServerConfig instance with validation.\n\t *\n\t * All values are validated and defaults are applied for undefined options.\n\t * Warnings are emitted to console for values outside recommended ranges.\n\t *\n\t * @param options - Optional configuration overrides\n\t *\n\t * @example\n\t * ```typescript\n\t * const config = new ServerConfig({\n\t * maxHistorySize: 500,\n\t * skillDirs: ['./my-skills']\n\t * });\n\t * ```\n\t */\n\tconstructor(options: ServerConfigOptions = {}) {\n\t\tthis.maxHistorySize = this.validateMaxHistorySize(options.maxHistorySize);\n\t\tthis.maxBranches = this.validateMaxBranches(options.maxBranches);\n\t\tthis.maxBranchSize = this.validateMaxBranchSize(options.maxBranchSize);\n\t\tthis.skillDirs = this.validateSkillDirs(options.skillDirs);\n\t\tthis.toolDirs = this.validateToolDirs(options.toolDirs);\n\t\tthis.discoveryCache = this.validateDiscoveryCache(options.discoveryCache);\n\t\tthis.persistence = this.validatePersistence(options.persistence);\n\t\tthis.persistenceBufferSize = this.validatePersistenceBufferSize(options.persistenceBufferSize);\n\t\tthis.persistenceFlushInterval = this.validatePersistenceFlushInterval(\n\t\t\toptions.persistenceFlushInterval\n\t\t);\n\t\tthis.persistenceMaxRetries = this.validatePersistenceMaxRetries(options.persistenceMaxRetries);\n\t\tthis.features = this.validateFeatures(options.features);\n\t\tthis.toolInterleaveTtlMs = this.validatePositiveMs(\n\t\t\toptions.toolInterleaveTtlMs,\n\t\t\t60000,\n\t\t\t'toolInterleaveTtlMs'\n\t\t);\n\t\tthis.toolInterleaveSweepMs = this.validatePositiveMs(\n\t\t\toptions.toolInterleaveSweepMs,\n\t\t\t60000,\n\t\t\t'toolInterleaveSweepMs'\n\t\t);\n\t\tthis.maxSessionsPerOwner = this.validateMaxSessionsPerOwner(options.maxSessionsPerOwner);\n\t}\n\n\t/**\n\t * Validates the max history size value.\n\t * @param value - The value to validate\n\t * @returns The validated value or default (1000)\n\t * @private\n\t */\n\tprivate validateMaxHistorySize(value?: number): number {\n\t\tconst defaultValue = 10000;\n\t\tif (value === undefined || value === null) return defaultValue;\n\t\tif (typeof value !== 'number' || !Number.isFinite(value)) {\n\t\t\tthrow new ConfigurationError(`maxHistorySize must be a finite number, got ${value}`);\n\t\t}\n\t\tif (value < 1) {\n\t\t\tthrow new ConfigurationError(`maxHistorySize must be at least 1, got ${value}`);\n\t\t}\n\t\tif (value > 10000) {\n\t\t\tthrow new ConfigurationError(`maxHistorySize must not exceed 10000, got ${value}`);\n\t\t}\n\t\treturn value;\n\t}\n\n\t/**\n\t * Validates the max branches value.\n\t * @param value - The value to validate\n\t * @returns The validated value or default (50)\n\t * @private\n\t */\n\tprivate validateMaxBranches(value?: number): number {\n\t\tconst defaultValue = 50;\n\t\tif (value === undefined || value === null) return defaultValue;\n\t\tif (typeof value !== 'number' || !Number.isFinite(value)) {\n\t\t\tthrow new ConfigurationError(`maxBranches must be a finite number, got ${value}`);\n\t\t}\n\t\tif (value < 0) {\n\t\t\tthrow new ConfigurationError(`maxBranches must be non-negative, got ${value}`);\n\t\t}\n\t\tif (value > 1000) {\n\t\t\tthrow new ConfigurationError(`maxBranches must not exceed 1000, got ${value}`);\n\t\t}\n\t\treturn value;\n\t}\n\n\t/**\n\t * Validates the max branch size value.\n\t * @param value - The value to validate\n\t * @returns The validated value or default (100)\n\t * @private\n\t */\n\tprivate validateMaxBranchSize(value?: number): number {\n\t\tconst defaultValue = 100;\n\t\tif (value === undefined || value === null) return defaultValue;\n\t\tif (typeof value !== 'number' || !Number.isFinite(value)) {\n\t\t\tthrow new ConfigurationError(`maxBranchSize must be a finite number, got ${value}`);\n\t\t}\n\t\tif (value < 1) {\n\t\t\tthrow new ConfigurationError(`maxBranchSize must be at least 1, got ${value}`);\n\t\t}\n\t\tif (value > 1000) {\n\t\t\tthrow new ConfigurationError(`maxBranchSize must not exceed 1000, got ${value}`);\n\t\t}\n\t\treturn value;\n\t}\n\n\t/**\n\t * Validates the skill directories value.\n\t * @param value - The value to validate\n\t * @returns The validated value or default ['.claude/skills', '~/.claude/skills', '.agents/skills', '~/.agents/skills']\n\t * @private\n\t */\n\tprivate validateSkillDirs(value?: string[]): string[] {\n\t\tconst defaultValue = [\n\t\t\t'.claude/skills',\n\t\t\tjoin(homedir(), '.claude/skills'),\n\t\t\t'.agents/skills',\n\t\t\tjoin(homedir(), '.agents/skills'),\n\t\t];\n\t\treturn value === undefined ? defaultValue : [...value];\n\t}\n\n\tprivate validateToolDirs(value?: string[]): string[] {\n\t\tconst defaultValue = ['.claude/tools', join(homedir(), '.claude/tools')];\n\t\treturn value === undefined ? defaultValue : [...value];\n\t}\n\n\t/**\n\t * Validates the discovery cache configuration.\n\t * @param value - The value to validate\n\t * @returns The validated value with defaults applied\n\t * @private\n\t */\n\tprivate validateDiscoveryCache(value?: { ttl?: number; maxSize?: number }): {\n\t\tttl: number;\n\t\tmaxSize: number;\n\t} {\n\t\treturn {\n\t\t\tttl: value?.ttl ?? 300000,\n\t\t\tmaxSize: value?.maxSize ?? 100,\n\t\t};\n\t}\n\n\t/**\n\t * Validates the persistence configuration.\n\t * @param value - The value to validate\n\t * @returns The validated value with defaults applied\n\t * @private\n\t */\n\tprivate validatePersistence(value?: PersistenceConfig): PersistenceConfig {\n\t\tif (!value) {\n\t\t\t// Default to in-memory (no actual persistence, just consistency)\n\t\t\treturn {\n\t\t\t\tenabled: false,\n\t\t\t\tbackend: 'memory',\n\t\t\t};\n\t\t}\n\n\t\t// Validate backend type\n\t\tconst validBackends = ['file', 'sqlite', 'memory'];\n\t\tconst backend = value.backend ?? 'memory';\n\t\tif (!validBackends.includes(backend)) {\n\t\t\tthrow new ConfigurationError(\n\t\t\t\t`persistence.backend must be one of ${validBackends.join(', ')}, got ${backend}`\n\t\t\t);\n\t\t}\n\n\t\treturn {\n\t\t\tenabled: value.enabled ?? false,\n\t\t\tbackend,\n\t\t\toptions: value.options ?? {},\n\t\t};\n\t}\n\n\t/**\n\t * Validates the persistence buffer size value.\n\t * @param value - The value to validate\n\t * @returns The validated value or default (100)\n\t * @private\n\t */\n\tprivate validatePersistenceBufferSize(value?: number): number {\n\t\tconst defaultValue = 100;\n\t\tif (value === undefined || value === null) return defaultValue;\n\t\tif (typeof value !== 'number' || !Number.isFinite(value)) {\n\t\t\tthrow new ConfigurationError(`persistenceBufferSize must be a finite number, got ${value}`);\n\t\t}\n\t\tif (value < 1) {\n\t\t\tthrow new ConfigurationError(`persistenceBufferSize must be at least 1, got ${value}`);\n\t\t}\n\t\tif (value > 10000) {\n\t\t\tthrow new ConfigurationError(`persistenceBufferSize must not exceed 10000, got ${value}`);\n\t\t}\n\t\treturn value;\n\t}\n\n\t/**\n\t * Validates the persistence flush interval value.\n\t * @param value - The value to validate\n\t * @returns The validated value or default (1000)\n\t * @private\n\t */\n\tprivate validatePersistenceFlushInterval(value?: number): number {\n\t\tconst defaultValue = 1000;\n\t\tif (value === undefined || value === null) return defaultValue;\n\t\tif (typeof value !== 'number' || !Number.isFinite(value)) {\n\t\t\tthrow new ConfigurationError(\n\t\t\t\t`persistenceFlushInterval must be a finite number, got ${value}`\n\t\t\t);\n\t\t}\n\t\tif (value < 100) {\n\t\t\tthrow new ConfigurationError(`persistenceFlushInterval must be at least 100, got ${value}`);\n\t\t}\n\t\tif (value > 60000) {\n\t\t\tthrow new ConfigurationError(`persistenceFlushInterval must not exceed 60000, got ${value}`);\n\t\t}\n\t\treturn value;\n\t}\n\n\t/**\n\t * Validates the persistence max retries value.\n\t * @param value - The value to validate\n\t * @returns The validated value or default (3)\n\t * @private\n\t */\n\tprivate validatePersistenceMaxRetries(value?: number): number {\n\t\tconst defaultValue = 3;\n\t\tif (value === undefined || value === null) return defaultValue;\n\t\tif (typeof value !== 'number' || !Number.isFinite(value)) {\n\t\t\tthrow new ConfigurationError(`persistenceMaxRetries must be a finite number, got ${value}`);\n\t\t}\n\t\tif (value < 0) {\n\t\t\tthrow new ConfigurationError(`persistenceMaxRetries must be non-negative, got ${value}`);\n\t\t}\n\t\tif (value > 10) {\n\t\t\tthrow new ConfigurationError(`persistenceMaxRetries must not exceed 10, got ${value}`);\n\t\t}\n\t\treturn value;\n\t}\n\n\t/**\n\t * Validates feature flags and fills defaults for missing fields.\n\t * @param value - Partial feature flag overrides\n\t * @returns Fully populated FeatureFlags with defaults applied\n\t * @private\n\t */\n\tprivate validateFeatures(value?: Partial<FeatureFlags>): FeatureFlags {\n\t\tconst reasoningStrategy = value?.reasoningStrategy ?? 'sequential';\n\t\tif (reasoningStrategy !== 'sequential' && reasoningStrategy !== 'tot') {\n\t\t\tthrow new ConfigurationError(\n\t\t\t\t`features.reasoningStrategy must be one of sequential, tot, got ${reasoningStrategy}`\n\t\t\t);\n\t\t}\n\t\treturn {\n\t\t\tdagEdges: value?.dagEdges ?? true,\n\t\t\treasoningStrategy,\n\t\t\tcalibration: value?.calibration ?? true,\n\t\t\tcompression: value?.compression ?? true,\n\t\t\ttoolInterleave: value?.toolInterleave ?? true,\n\t\t\tnewThoughtTypes: value?.newThoughtTypes ?? true,\n\t\t\toutcomeRecording: value?.outcomeRecording ?? true,\n\t\t};\n\t}\n\n\t/**\n\t * Validates a positive millisecond value with a default fallback.\n\t * @param value - The value to validate\n\t * @param defaultValue - Default applied if value is undefined/null\n\t * @param fieldName - Field name for error messages\n\t * @returns The validated millisecond value\n\t * @private\n\t */\n\tprivate validatePositiveMs(\n\t\tvalue: number | undefined,\n\t\tdefaultValue: number,\n\t\tfieldName: string\n\t): number {\n\t\tif (value === undefined || value === null) return defaultValue;\n\t\tif (typeof value !== 'number' || !Number.isFinite(value)) {\n\t\t\tthrow new ConfigurationError(`${fieldName} must be a finite number, got ${value}`);\n\t\t}\n\t\tif (value < 1) {\n\t\t\tthrow new ConfigurationError(`${fieldName} must be at least 1, got ${value}`);\n\t\t}\n\t\treturn value;\n\t}\n\n\t/**\n\t * Validates the max sessions per owner value.\n\t * @param value - The value to validate\n\t * @returns The validated value or default (50)\n\t * @private\n\t */\n\tprivate validateMaxSessionsPerOwner(value?: number): number {\n\t\tconst defaultValue = 50;\n\t\tif (value === undefined || value === null) return defaultValue;\n\t\tif (typeof value !== 'number' || !Number.isFinite(value)) {\n\t\t\tthrow new ConfigurationError(`maxSessionsPerOwner must be a finite number, got ${value}`);\n\t\t}\n\t\tif (value < 1) {\n\t\t\tthrow new ConfigurationError(`maxSessionsPerOwner must be at least 1, got ${value}`);\n\t\t}\n\t\tif (value > 10000) {\n\t\t\tthrow new ConfigurationError(`maxSessionsPerOwner must not exceed 10000, got ${value}`);\n\t\t}\n\t\treturn value;\n\t}\n\n\t/**\n\t * Converts the configuration to a plain object.\n\t *\n\t * Useful for serialization, logging, or when a plain object representation\n\t * is preferred over the ServerConfig instance.\n\t *\n\t * @returns A plain object representation of the configuration\n\t *\n\t * @example\n\t * ```typescript\n\t * const config = new ServerConfig({ maxHistorySize: 500 });\n\t * const json = config.toJSON();\n\t * console.log(JSON.stringify(json, null, 2));\n\t * ```\n\t */\n\tpublic toJSON(): ServerConfigOptions {\n\t\treturn {\n\t\t\tmaxHistorySize: this.maxHistorySize,\n\t\t\tmaxBranches: this.maxBranches,\n\t\t\tmaxBranchSize: this.maxBranchSize,\n\t\t\tskillDirs: this.skillDirs,\n\t\t\ttoolDirs: this.toolDirs,\n\t\t\tdiscoveryCache: this.discoveryCache,\n\t\t\tpersistence: this.persistence,\n\t\t\tpersistenceBufferSize: this.persistenceBufferSize,\n\t\t\tpersistenceFlushInterval: this.persistenceFlushInterval,\n\t\t\tpersistenceMaxRetries: this.persistenceMaxRetries,\n\t\t\tfeatures: this.features,\n\t\t\ttoolInterleaveTtlMs: this.toolInterleaveTtlMs,\n\t\t\ttoolInterleaveSweepMs: this.toolInterleaveSweepMs,\n\t\t\tmaxSessionsPerOwner: this.maxSessionsPerOwner,\n\t\t};\n\t}\n}\n"],"names":["ServerConfig","options","value","defaultValue","Number","ConfigurationError","join","homedir","undefined","validBackends","backend","reasoningStrategy","fieldName"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"ServerConfig.js","sources":["../src/ServerConfig.ts"],"sourcesContent":["/**\n * Server configuration management with validation.\n *\n * This module provides the `ServerConfig` class which handles all server configuration\n * with built-in validation and sensible defaults. Configuration values are validated\n * on construction and warnings are emitted for out-of-range values.\n *\n * @module ServerConfig\n */\n\nimport { homedir } from 'node:os';\nimport { join } from 'node:path';\nimport { ConfigurationError } from './errors.js';\nimport type { PersistenceConfig } from './contracts/PersistenceBackend.js';\n\n/**\n * Configuration options for creating a `ServerConfig` instance.\n *\n * All properties are optional with sensible defaults applied during validation.\n *\n * @example\n * ```typescript\n * const options: ServerConfigOptions = {\n * maxHistorySize: 500,\n * maxBranches: 25,\n * skillDirs: ['./custom-skills'],\n * toolDirs: ['./custom-tools'],\n * persistence: { enabled: true, backend: 'sqlite' }\n * };\n * ```\n */\n\nimport type { FeatureFlags } from './contracts/features.js';\nexport interface ServerConfigOptions {\n\t/**\n\t * Maximum number of thoughts to keep in history.\n\t * @default 10000\n\t */\n\tmaxHistorySize?: number;\n\n\t/**\n\t * Maximum number of branches to maintain.\n\t * @default 50\n\t */\n\tmaxBranches?: number;\n\n\t/**\n\t * Maximum size of each branch.\n\t * @default 100\n\t */\n\tmaxBranchSize?: number;\n\n\t/**\n\t * Directory paths to search for skills.\n\t * @default Project .claude/skills and .agents/skills, plus both paths under the home directory\n\t */\n\tskillDirs?: string[];\n\n\t/**\n\t * Directory paths to search for tools.\n\t * @default ['.claude/tools', '~/.claude/tools']\n\t */\n\ttoolDirs?: string[];\n\n\t/**\n\t * Discovery cache configuration.\n\t */\n\tdiscoveryCache?: {\n\t\t/**\n\t\t * Time-to-live for cache entries in milliseconds.\n\t\t * @default 300000 (5 minutes)\n\t\t */\n\t\tttl?: number;\n\t\t/**\n\t\t * Maximum number of entries in the cache.\n\t\t * @default 100\n\t\t */\n\t\tmaxSize?: number;\n\t};\n\n\t/**\n\t * Persistence configuration for storing history and state.\n\t */\n\tpersistence?: PersistenceConfig;\n\n\t/**\n\t * Maximum number of thoughts to buffer before flushing to persistence.\n\t * YAML/JSON only; no environment override.\n\t * @default 100\n\t */\n\tpersistenceBufferSize?: number;\n\n\t/**\n\t * Interval in milliseconds between periodic persistence flushes.\n\t * YAML/JSON only; no environment override.\n\t * @default 1000\n\t */\n\tpersistenceFlushInterval?: number;\n\n\t/**\n\t * Maximum number of retries for failed persistence flushes.\n\t * YAML/JSON only; no environment override.\n\t * @default 3\n\t */\n\tpersistenceMaxRetries?: number;\n\n\t/**\n\t * Feature flag overrides. Missing fields are filled with defaults (all ON,\n\t * reasoningStrategy='sequential').\n\t */\n\tfeatures?: Partial<FeatureFlags>;\n\n\t/**\n\t * TTL in milliseconds for suspended tool-interleave entries in SuspensionStore.\n\t * @default 60000\n\t */\n\ttoolInterleaveTtlMs?: number;\n\n\t/**\n\t * Sweep interval in milliseconds for SuspensionStore expiration cleanup.\n\t * @default 60000\n\t */\n\ttoolInterleaveSweepMs?: number;\n\n\t/**\n\t * Maximum sessions per owner. Prevents one user from consuming all session slots.\n\t * @default 50\n\t */\n\tmaxSessionsPerOwner?: number;\n}\n\n/**\n * Server configuration with validation and defaults.\n *\n * This class manages all server configuration including history limits,\n * branch limits, discovery directories, cache settings, and persistence.\n * All values are validated on construction with appropriate defaults applied.\n *\n * @remarks\n * - Values outside recommended ranges trigger warnings but are still applied\n * - Supported environment variables override file-based configuration through ConfigLoader\n * - Logging uses file/environment input separately; ServerConfig does not hold log settings\n * - The `toJSON()` method provides a plain object representation\n *\n * @example\n * ```typescript\n * // Using defaults\n * const config1 = new ServerConfig();\n * console.log(config1.maxHistorySize); // 10000\n *\n * // With custom options\n * const config2 = new ServerConfig({\n * maxHistorySize: 500,\n * persistence: { enabled: true, backend: 'file', options: { dataDir: './data' } }\n * });\n *\n * // Export as plain object\n * const json = config2.toJSON();\n * ```\n */\nexport class ServerConfig {\n\t/** Maximum number of thoughts to keep in history. */\n\tpublic maxHistorySize: number;\n\n\t/** Maximum number of branches to maintain. */\n\tpublic maxBranches: number;\n\n\t/** Maximum size of each branch. */\n\tpublic maxBranchSize: number;\n\n\t/** Directory paths to search for skills. */\n\tpublic skillDirs: string[];\n\n\t/** Directory paths to search for tools. */\n\tpublic toolDirs: string[];\n\n\t/** Discovery cache configuration. */\n\tpublic discoveryCache: { ttl: number; maxSize: number };\n\n\t/** Persistence configuration. */\n\tpublic persistence: PersistenceConfig;\n\n\t/** Maximum number of thoughts to buffer before flushing to persistence. */\n\tpublic persistenceBufferSize: number;\n\n\t/** Interval in milliseconds between periodic persistence flushes. */\n\tpublic persistenceFlushInterval: number;\n\n\t/** Maximum number of retries for failed persistence flushes. */\n\tpublic persistenceMaxRetries: number;\n\n\t/** Feature flag toggles. */\n\tpublic features: FeatureFlags;\n\n\t/** TTL in milliseconds for suspended tool-interleave entries. */\n\tpublic toolInterleaveTtlMs: number;\n\n\t/** Sweep interval in milliseconds for SuspensionStore expiration cleanup. */\n\tpublic toolInterleaveSweepMs: number;\n\n\t/** Maximum sessions per owner (LRU per-owner bucket). */\n\tpublic maxSessionsPerOwner: number;\n\n\t/**\n\t * Creates a new ServerConfig instance with validation.\n\t *\n\t * All values are validated and defaults are applied for undefined options.\n\t * Warnings are emitted to console for values outside recommended ranges.\n\t *\n\t * @param options - Optional configuration overrides\n\t *\n\t * @example\n\t * ```typescript\n\t * const config = new ServerConfig({\n\t * maxHistorySize: 500,\n\t * skillDirs: ['./my-skills']\n\t * });\n\t * ```\n\t */\n\tconstructor(options: ServerConfigOptions = {}) {\n\t\tthis.maxHistorySize = this.validateMaxHistorySize(options.maxHistorySize);\n\t\tthis.maxBranches = this.validateMaxBranches(options.maxBranches);\n\t\tthis.maxBranchSize = this.validateMaxBranchSize(options.maxBranchSize);\n\t\tthis.skillDirs = this.validateSkillDirs(options.skillDirs);\n\t\tthis.toolDirs = this.validateToolDirs(options.toolDirs);\n\t\tthis.discoveryCache = this.validateDiscoveryCache(options.discoveryCache);\n\t\tthis.persistence = this.validatePersistence(options.persistence);\n\t\tthis.persistenceBufferSize = this.validatePersistenceBufferSize(options.persistenceBufferSize);\n\t\tthis.persistenceFlushInterval = this.validatePersistenceFlushInterval(\n\t\t\toptions.persistenceFlushInterval\n\t\t);\n\t\tthis.persistenceMaxRetries = this.validatePersistenceMaxRetries(options.persistenceMaxRetries);\n\t\tthis.features = this.validateFeatures(options.features);\n\t\tthis.toolInterleaveTtlMs = this.validatePositiveMs(\n\t\t\toptions.toolInterleaveTtlMs,\n\t\t\t60000,\n\t\t\t'toolInterleaveTtlMs'\n\t\t);\n\t\tthis.toolInterleaveSweepMs = this.validatePositiveMs(\n\t\t\toptions.toolInterleaveSweepMs,\n\t\t\t60000,\n\t\t\t'toolInterleaveSweepMs'\n\t\t);\n\t\tthis.maxSessionsPerOwner = this.validateMaxSessionsPerOwner(options.maxSessionsPerOwner);\n\t}\n\n\t/**\n\t * Validates the max history size value.\n\t * @param value - The value to validate\n\t * @returns The validated value or default (10000)\n\t * @private\n\t */\n\tprivate validateMaxHistorySize(value?: number): number {\n\t\tconst defaultValue = 10000;\n\t\tif (value === undefined || value === null) return defaultValue;\n\t\tif (typeof value !== 'number' || !Number.isFinite(value)) {\n\t\t\tthrow new ConfigurationError(`maxHistorySize must be a finite number, got ${value}`);\n\t\t}\n\t\tif (value < 1) {\n\t\t\tthrow new ConfigurationError(`maxHistorySize must be at least 1, got ${value}`);\n\t\t}\n\t\tif (value > 10000) {\n\t\t\tthrow new ConfigurationError(`maxHistorySize must not exceed 10000, got ${value}`);\n\t\t}\n\t\treturn value;\n\t}\n\n\t/**\n\t * Validates the max branches value.\n\t * @param value - The value to validate\n\t * @returns The validated value or default (50)\n\t * @private\n\t */\n\tprivate validateMaxBranches(value?: number): number {\n\t\tconst defaultValue = 50;\n\t\tif (value === undefined || value === null) return defaultValue;\n\t\tif (typeof value !== 'number' || !Number.isFinite(value)) {\n\t\t\tthrow new ConfigurationError(`maxBranches must be a finite number, got ${value}`);\n\t\t}\n\t\tif (value < 0) {\n\t\t\tthrow new ConfigurationError(`maxBranches must be non-negative, got ${value}`);\n\t\t}\n\t\tif (value > 1000) {\n\t\t\tthrow new ConfigurationError(`maxBranches must not exceed 1000, got ${value}`);\n\t\t}\n\t\treturn value;\n\t}\n\n\t/**\n\t * Validates the max branch size value.\n\t * @param value - The value to validate\n\t * @returns The validated value or default (100)\n\t * @private\n\t */\n\tprivate validateMaxBranchSize(value?: number): number {\n\t\tconst defaultValue = 100;\n\t\tif (value === undefined || value === null) return defaultValue;\n\t\tif (typeof value !== 'number' || !Number.isFinite(value)) {\n\t\t\tthrow new ConfigurationError(`maxBranchSize must be a finite number, got ${value}`);\n\t\t}\n\t\tif (value < 1) {\n\t\t\tthrow new ConfigurationError(`maxBranchSize must be at least 1, got ${value}`);\n\t\t}\n\t\tif (value > 1000) {\n\t\t\tthrow new ConfigurationError(`maxBranchSize must not exceed 1000, got ${value}`);\n\t\t}\n\t\treturn value;\n\t}\n\n\t/**\n\t * Validates the skill directories value.\n\t * @param value - The value to validate\n\t * @returns The validated value or project-local and home-directory .claude/.agents skill paths\n\t * @private\n\t */\n\tprivate validateSkillDirs(value?: string[]): string[] {\n\t\tconst defaultValue = [\n\t\t\t'.claude/skills',\n\t\t\tjoin(homedir(), '.claude/skills'),\n\t\t\t'.agents/skills',\n\t\t\tjoin(homedir(), '.agents/skills'),\n\t\t];\n\t\treturn value === undefined ? defaultValue : [...value];\n\t}\n\n\tprivate validateToolDirs(value?: string[]): string[] {\n\t\tconst defaultValue = ['.claude/tools', join(homedir(), '.claude/tools')];\n\t\treturn value === undefined ? defaultValue : [...value];\n\t}\n\n\t/**\n\t * Validates the discovery cache configuration.\n\t * @param value - The value to validate\n\t * @returns The validated value with defaults applied\n\t * @private\n\t */\n\tprivate validateDiscoveryCache(value?: { ttl?: number; maxSize?: number }): {\n\t\tttl: number;\n\t\tmaxSize: number;\n\t} {\n\t\treturn {\n\t\t\tttl: value?.ttl ?? 300000,\n\t\t\tmaxSize: value?.maxSize ?? 100,\n\t\t};\n\t}\n\n\t/**\n\t * Validates the persistence configuration.\n\t * @param value - The value to validate\n\t * @returns The validated value with defaults applied\n\t * @private\n\t */\n\tprivate validatePersistence(value?: PersistenceConfig): PersistenceConfig {\n\t\tif (!value) {\n\t\t\t// Default to in-memory (no actual persistence, just consistency)\n\t\t\treturn {\n\t\t\t\tenabled: false,\n\t\t\t\tbackend: 'memory',\n\t\t\t};\n\t\t}\n\n\t\t// Validate backend type\n\t\tconst validBackends = ['file', 'sqlite', 'memory'];\n\t\tconst backend = value.backend ?? 'memory';\n\t\tif (!validBackends.includes(backend)) {\n\t\t\tthrow new ConfigurationError(\n\t\t\t\t`persistence.backend must be one of ${validBackends.join(', ')}, got ${backend}`\n\t\t\t);\n\t\t}\n\n\t\treturn {\n\t\t\tenabled: value.enabled ?? false,\n\t\t\tbackend,\n\t\t\toptions: value.options ?? {},\n\t\t};\n\t}\n\n\t/**\n\t * Validates the persistence buffer size value.\n\t * @param value - The value to validate\n\t * @returns The validated value or default (100)\n\t * @private\n\t */\n\tprivate validatePersistenceBufferSize(value?: number): number {\n\t\tconst defaultValue = 100;\n\t\tif (value === undefined || value === null) return defaultValue;\n\t\tif (typeof value !== 'number' || !Number.isFinite(value)) {\n\t\t\tthrow new ConfigurationError(`persistenceBufferSize must be a finite number, got ${value}`);\n\t\t}\n\t\tif (value < 1) {\n\t\t\tthrow new ConfigurationError(`persistenceBufferSize must be at least 1, got ${value}`);\n\t\t}\n\t\tif (value > 10000) {\n\t\t\tthrow new ConfigurationError(`persistenceBufferSize must not exceed 10000, got ${value}`);\n\t\t}\n\t\treturn value;\n\t}\n\n\t/**\n\t * Validates the persistence flush interval value.\n\t * @param value - The value to validate\n\t * @returns The validated value or default (1000)\n\t * @private\n\t */\n\tprivate validatePersistenceFlushInterval(value?: number): number {\n\t\tconst defaultValue = 1000;\n\t\tif (value === undefined || value === null) return defaultValue;\n\t\tif (typeof value !== 'number' || !Number.isFinite(value)) {\n\t\t\tthrow new ConfigurationError(\n\t\t\t\t`persistenceFlushInterval must be a finite number, got ${value}`\n\t\t\t);\n\t\t}\n\t\tif (value < 100) {\n\t\t\tthrow new ConfigurationError(`persistenceFlushInterval must be at least 100, got ${value}`);\n\t\t}\n\t\tif (value > 60000) {\n\t\t\tthrow new ConfigurationError(`persistenceFlushInterval must not exceed 60000, got ${value}`);\n\t\t}\n\t\treturn value;\n\t}\n\n\t/**\n\t * Validates the persistence max retries value.\n\t * @param value - The value to validate\n\t * @returns The validated value or default (3)\n\t * @private\n\t */\n\tprivate validatePersistenceMaxRetries(value?: number): number {\n\t\tconst defaultValue = 3;\n\t\tif (value === undefined || value === null) return defaultValue;\n\t\tif (typeof value !== 'number' || !Number.isFinite(value)) {\n\t\t\tthrow new ConfigurationError(`persistenceMaxRetries must be a finite number, got ${value}`);\n\t\t}\n\t\tif (value < 0) {\n\t\t\tthrow new ConfigurationError(`persistenceMaxRetries must be non-negative, got ${value}`);\n\t\t}\n\t\tif (value > 10) {\n\t\t\tthrow new ConfigurationError(`persistenceMaxRetries must not exceed 10, got ${value}`);\n\t\t}\n\t\treturn value;\n\t}\n\n\t/**\n\t * Validates feature flags and fills defaults for missing fields.\n\t * @param value - Partial feature flag overrides\n\t * @returns Fully populated FeatureFlags with defaults applied\n\t * @private\n\t */\n\tprivate validateFeatures(value?: Partial<FeatureFlags>): FeatureFlags {\n\t\tconst reasoningStrategy = value?.reasoningStrategy ?? 'sequential';\n\t\tif (reasoningStrategy !== 'sequential' && reasoningStrategy !== 'tot') {\n\t\t\tthrow new ConfigurationError(\n\t\t\t\t`features.reasoningStrategy must be one of sequential, tot, got ${reasoningStrategy}`\n\t\t\t);\n\t\t}\n\t\treturn {\n\t\t\tdagEdges: value?.dagEdges ?? true,\n\t\t\treasoningStrategy,\n\t\t\tcalibration: value?.calibration ?? true,\n\t\t\tcompression: value?.compression ?? true,\n\t\t\ttoolInterleave: value?.toolInterleave ?? true,\n\t\t\tnewThoughtTypes: value?.newThoughtTypes ?? true,\n\t\t\toutcomeRecording: value?.outcomeRecording ?? true,\n\t\t};\n\t}\n\n\t/**\n\t * Validates a positive millisecond value with a default fallback.\n\t * @param value - The value to validate\n\t * @param defaultValue - Default applied if value is undefined/null\n\t * @param fieldName - Field name for error messages\n\t * @returns The validated millisecond value\n\t * @private\n\t */\n\tprivate validatePositiveMs(\n\t\tvalue: number | undefined,\n\t\tdefaultValue: number,\n\t\tfieldName: string\n\t): number {\n\t\tif (value === undefined || value === null) return defaultValue;\n\t\tif (typeof value !== 'number' || !Number.isFinite(value)) {\n\t\t\tthrow new ConfigurationError(`${fieldName} must be a finite number, got ${value}`);\n\t\t}\n\t\tif (value < 1) {\n\t\t\tthrow new ConfigurationError(`${fieldName} must be at least 1, got ${value}`);\n\t\t}\n\t\treturn value;\n\t}\n\n\t/**\n\t * Validates the max sessions per owner value.\n\t * @param value - The value to validate\n\t * @returns The validated value or default (50)\n\t * @private\n\t */\n\tprivate validateMaxSessionsPerOwner(value?: number): number {\n\t\tconst defaultValue = 50;\n\t\tif (value === undefined || value === null) return defaultValue;\n\t\tif (typeof value !== 'number' || !Number.isFinite(value)) {\n\t\t\tthrow new ConfigurationError(`maxSessionsPerOwner must be a finite number, got ${value}`);\n\t\t}\n\t\tif (value < 1) {\n\t\t\tthrow new ConfigurationError(`maxSessionsPerOwner must be at least 1, got ${value}`);\n\t\t}\n\t\tif (value > 10000) {\n\t\t\tthrow new ConfigurationError(`maxSessionsPerOwner must not exceed 10000, got ${value}`);\n\t\t}\n\t\treturn value;\n\t}\n\n\t/**\n\t * Converts the configuration to a plain object.\n\t *\n\t * Useful for serialization, logging, or when a plain object representation\n\t * is preferred over the ServerConfig instance.\n\t *\n\t * @returns A plain object representation of the configuration\n\t *\n\t * @example\n\t * ```typescript\n\t * const config = new ServerConfig({ maxHistorySize: 500 });\n\t * const json = config.toJSON();\n\t * console.log(JSON.stringify(json, null, 2));\n\t * ```\n\t */\n\tpublic toJSON(): ServerConfigOptions {\n\t\treturn {\n\t\t\tmaxHistorySize: this.maxHistorySize,\n\t\t\tmaxBranches: this.maxBranches,\n\t\t\tmaxBranchSize: this.maxBranchSize,\n\t\t\tskillDirs: this.skillDirs,\n\t\t\ttoolDirs: this.toolDirs,\n\t\t\tdiscoveryCache: this.discoveryCache,\n\t\t\tpersistence: this.persistence,\n\t\t\tpersistenceBufferSize: this.persistenceBufferSize,\n\t\t\tpersistenceFlushInterval: this.persistenceFlushInterval,\n\t\t\tpersistenceMaxRetries: this.persistenceMaxRetries,\n\t\t\tfeatures: this.features,\n\t\t\ttoolInterleaveTtlMs: this.toolInterleaveTtlMs,\n\t\t\ttoolInterleaveSweepMs: this.toolInterleaveSweepMs,\n\t\t\tmaxSessionsPerOwner: this.maxSessionsPerOwner,\n\t\t};\n\t}\n}\n"],"names":["ServerConfig","options","value","defaultValue","Number","ConfigurationError","join","homedir","undefined","validBackends","backend","reasoningStrategy","fieldName"],"mappings":"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"}
|
|
@@ -3,7 +3,7 @@
|
|
|
3
3
|
*
|
|
4
4
|
* This module provides the `ConfigLoader` class which handles loading configuration
|
|
5
5
|
* from YAML and JSON files in standard locations, with automatic environment variable
|
|
6
|
-
* overrides for
|
|
6
|
+
* overrides for supported settings. Persistence buffer, flush, and retry settings are file-only.
|
|
7
7
|
*
|
|
8
8
|
* @module config
|
|
9
9
|
*/
|
|
@@ -14,8 +14,8 @@ import type { ServerConfigOptions } from '../ServerConfig.js';
|
|
|
14
14
|
* Configuration options loaded from config files.
|
|
15
15
|
*
|
|
16
16
|
* These options represent the structure of configuration files (JSON or YAML)
|
|
17
|
-
* that can be loaded from standard locations.
|
|
18
|
-
*
|
|
17
|
+
* that can be loaded from standard locations. Only supported fields have
|
|
18
|
+
* environment overrides; persistence buffer, flush, and retry settings are file-only.
|
|
19
19
|
*
|
|
20
20
|
* @example
|
|
21
21
|
* ```yaml
|
|
@@ -94,8 +94,11 @@ export interface ConfigFileOptions {
|
|
|
94
94
|
* Persistence configuration for storing history and state.
|
|
95
95
|
*/
|
|
96
96
|
readonly persistence?: PersistenceConfig;
|
|
97
|
+
/** Maximum buffered thoughts before flushing; file-only (default 100 in ServerConfig). */
|
|
97
98
|
readonly persistenceBufferSize?: number;
|
|
99
|
+
/** Periodic flush interval in milliseconds; file-only (default 1000 in ServerConfig). */
|
|
98
100
|
readonly persistenceFlushInterval?: number;
|
|
101
|
+
/** Maximum flush retries; file-only (default 3 in ServerConfig). */
|
|
99
102
|
readonly persistenceMaxRetries?: number;
|
|
100
103
|
/**
|
|
101
104
|
* Feature flag overrides. Each field can be set independently.
|
|
@@ -124,11 +127,11 @@ export interface ConfigFileOptions {
|
|
|
124
127
|
*
|
|
125
128
|
* This class searches for configuration files in standard locations and applies
|
|
126
129
|
* environment variable overrides. Files are searched in priority order, with the
|
|
127
|
-
* first match being used.
|
|
130
|
+
* first valid match being used. Supported environment variables take precedence over file values.
|
|
128
131
|
*
|
|
129
132
|
* @remarks
|
|
130
133
|
* **Config File Search Order (priority):**
|
|
131
|
-
* 1. Custom path (if
|
|
134
|
+
* 1. Custom path or `TRACELATTICE_CONFIG` (if present, replaces the default search list)
|
|
132
135
|
* 2. `.claude/config.json` (project-local)
|
|
133
136
|
* 3. `.claude/config.yaml` (project-local)
|
|
134
137
|
* 4. `.claude/config.yml` (project-local)
|
|
@@ -148,6 +151,11 @@ export interface ConfigFileOptions {
|
|
|
148
151
|
* | `TRACELATTICE_TOOL_DIRS` | string | Colon-separated directory paths |
|
|
149
152
|
* | `TRACELATTICE_DISCOVERY_CACHE_TTL` | number | TTL in seconds (converted to ms) |
|
|
150
153
|
* | `TRACELATTICE_DISCOVERY_CACHE_MAX_SIZE` | number | Max cache entries |
|
|
154
|
+
* | `TRACELATTICE_TOOL_INTERLEAVE_TTL_MS` / `TRACELATTICE_TOOL_INTERLEAVE_SWEEP_MS` | number | Milliseconds |
|
|
155
|
+
* | `TRACELATTICE_SESSION_MAX_PER_OWNER` | number | Max sessions per owner |
|
|
156
|
+
* | `TRACELATTICE_FEATURES_*` | boolean or strategy | Feature toggles or `sequential`/`tot` |
|
|
157
|
+
*
|
|
158
|
+
* Persistence buffer size, flush interval (milliseconds), and retries are file-only.
|
|
151
159
|
*
|
|
152
160
|
* @example
|
|
153
161
|
* ```typescript
|
|
@@ -186,9 +194,10 @@ export declare class ConfigLoader {
|
|
|
186
194
|
*
|
|
187
195
|
* Searches for config files in the configured paths (in priority order),
|
|
188
196
|
* parses the first match, and applies environment variable overrides.
|
|
189
|
-
*
|
|
197
|
+
* A malformed file is logged and skipped. With no valid file, applies environment
|
|
198
|
+
* overrides to an empty object (the declared nullable return type does not return null).
|
|
190
199
|
*
|
|
191
|
-
* @returns The loaded configuration with environment overrides applied, or
|
|
200
|
+
* @returns The loaded configuration with environment overrides applied, or an empty/overlaid object
|
|
192
201
|
*
|
|
193
202
|
* @example
|
|
194
203
|
* ```typescript
|
|
@@ -215,6 +224,10 @@ export declare class ConfigLoader {
|
|
|
215
224
|
* - `TRACELATTICE_TOOL_DIRS` (colon-separated paths)
|
|
216
225
|
* - `TRACELATTICE_DISCOVERY_CACHE_TTL` (in seconds, converted to ms)
|
|
217
226
|
* - `TRACELATTICE_DISCOVERY_CACHE_MAX_SIZE` (number)
|
|
227
|
+
* - `TRACELATTICE_TOOL_INTERLEAVE_TTL_MS`, `TRACELATTICE_TOOL_INTERLEAVE_SWEEP_MS` (milliseconds)
|
|
228
|
+
* - `TRACELATTICE_SESSION_MAX_PER_OWNER` (number)
|
|
229
|
+
* - `TRACELATTICE_FEATURES_*` (booleans true/false/1/0 or sequential/tot strategy)
|
|
230
|
+
* Persistence buffer, flush interval, and retry settings have no environment aliases.
|
|
218
231
|
*
|
|
219
232
|
* @param config - The configuration to apply overrides to
|
|
220
233
|
* @returns A new configuration object with environment overrides applied
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"ConfigLoader.d.ts","sourceRoot":"","sources":["../../src/config/ConfigLoader.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG;AAOH,OAAO,KAAK,EAAE,iBAAiB,EAAE,MAAM,oCAAoC,CAAC;AAE5E,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,0BAA0B,CAAC;AAC7D,OAAO,KAAK,EAAE,mBAAmB,EAAE,MAAM,oBAAoB,CAAC;AAiC9D;;;;;;;;;;;;;;;;;;;;;;;;;;;GA2BG;AACH,MAAM,WAAW,iBAAiB;IACjC;;;OAGG;IACH,QAAQ,CAAC,cAAc,CAAC,EAAE,MAAM,CAAC;IAEjC;;;OAGG;IACH,QAAQ,CAAC,WAAW,CAAC,EAAE,MAAM,CAAC;IAE9B;;;OAGG;IACH,QAAQ,CAAC,aAAa,CAAC,EAAE,MAAM,CAAC;IAEhC;;;OAGG;IACH,QAAQ,CAAC,QAAQ,CAAC,EAAE,OAAO,GAAG,MAAM,GAAG,MAAM,GAAG,OAAO,CAAC;IAExD;;;OAGG;IACH,QAAQ,CAAC,SAAS,CAAC,EAAE,OAAO,CAAC;IAE7B;;;OAGG;IACH,QAAQ,CAAC,SAAS,CAAC,EAAE,MAAM,EAAE,CAAC;IAE9B;;;OAGG;IACH,QAAQ,CAAC,QAAQ,CAAC,EAAE,MAAM,EAAE,CAAC;IAE7B;;;;OAIG;IACH,QAAQ,CAAC,cAAc,CAAC,EAAE;QACzB;;;WAGG;QACH,QAAQ,CAAC,GAAG,CAAC,EAAE,MAAM,CAAC;QACtB;;WAEG;QACH,QAAQ,CAAC,OAAO,CAAC,EAAE,MAAM,CAAC;KAC1B,CAAC;IAEF;;OAEG;IACH,QAAQ,CAAC,WAAW,CAAC,EAAE,iBAAiB,CAAC;IAEzC,QAAQ,CAAC,qBAAqB,CAAC,EAAE,MAAM,CAAC;IAExC,QAAQ,CAAC,wBAAwB,CAAC,EAAE,MAAM,CAAC;IAE3C,QAAQ,CAAC,qBAAqB,CAAC,EAAE,MAAM,CAAC;IAExC;;;OAGG;IACH,QAAQ,CAAC,QAAQ,CAAC,EAAE,OAAO,CAAC,YAAY,CAAC,CAAC;IAE1C;;;OAGG;IACH,QAAQ,CAAC,mBAAmB,CAAC,EAAE,MAAM,CAAC;IAEtC;;;OAGG;IACH,QAAQ,CAAC,qBAAqB,CAAC,EAAE,MAAM,CAAC;IAExC;;;;OAIG;IACH,QAAQ,CAAC,mBAAmB,CAAC,EAAE,MAAM,CAAC;CACtC;AAED
|
|
1
|
+
{"version":3,"file":"ConfigLoader.d.ts","sourceRoot":"","sources":["../../src/config/ConfigLoader.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG;AAOH,OAAO,KAAK,EAAE,iBAAiB,EAAE,MAAM,oCAAoC,CAAC;AAE5E,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,0BAA0B,CAAC;AAC7D,OAAO,KAAK,EAAE,mBAAmB,EAAE,MAAM,oBAAoB,CAAC;AAiC9D;;;;;;;;;;;;;;;;;;;;;;;;;;;GA2BG;AACH,MAAM,WAAW,iBAAiB;IACjC;;;OAGG;IACH,QAAQ,CAAC,cAAc,CAAC,EAAE,MAAM,CAAC;IAEjC;;;OAGG;IACH,QAAQ,CAAC,WAAW,CAAC,EAAE,MAAM,CAAC;IAE9B;;;OAGG;IACH,QAAQ,CAAC,aAAa,CAAC,EAAE,MAAM,CAAC;IAEhC;;;OAGG;IACH,QAAQ,CAAC,QAAQ,CAAC,EAAE,OAAO,GAAG,MAAM,GAAG,MAAM,GAAG,OAAO,CAAC;IAExD;;;OAGG;IACH,QAAQ,CAAC,SAAS,CAAC,EAAE,OAAO,CAAC;IAE7B;;;OAGG;IACH,QAAQ,CAAC,SAAS,CAAC,EAAE,MAAM,EAAE,CAAC;IAE9B;;;OAGG;IACH,QAAQ,CAAC,QAAQ,CAAC,EAAE,MAAM,EAAE,CAAC;IAE7B;;;;OAIG;IACH,QAAQ,CAAC,cAAc,CAAC,EAAE;QACzB;;;WAGG;QACH,QAAQ,CAAC,GAAG,CAAC,EAAE,MAAM,CAAC;QACtB;;WAEG;QACH,QAAQ,CAAC,OAAO,CAAC,EAAE,MAAM,CAAC;KAC1B,CAAC;IAEF;;OAEG;IACH,QAAQ,CAAC,WAAW,CAAC,EAAE,iBAAiB,CAAC;IAEzC,0FAA0F;IAC1F,QAAQ,CAAC,qBAAqB,CAAC,EAAE,MAAM,CAAC;IAExC,yFAAyF;IACzF,QAAQ,CAAC,wBAAwB,CAAC,EAAE,MAAM,CAAC;IAE3C,oEAAoE;IACpE,QAAQ,CAAC,qBAAqB,CAAC,EAAE,MAAM,CAAC;IAExC;;;OAGG;IACH,QAAQ,CAAC,QAAQ,CAAC,EAAE,OAAO,CAAC,YAAY,CAAC,CAAC;IAE1C;;;OAGG;IACH,QAAQ,CAAC,mBAAmB,CAAC,EAAE,MAAM,CAAC;IAEtC;;;OAGG;IACH,QAAQ,CAAC,qBAAqB,CAAC,EAAE,MAAM,CAAC;IAExC;;;;OAIG;IACH,QAAQ,CAAC,mBAAmB,CAAC,EAAE,MAAM,CAAC;CACtC;AAED;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAgDG;AACH,qBAAa,YAAY;IACxB,+DAA+D;IAC/D,OAAO,CAAC,YAAY,CAAW;IAE/B;;;;;;;;;;;;;OAaG;gBACS,UAAU,CAAC,EAAE,MAAM;IAc/B;;;;;;;;;;;;;;;;;;;;OAoBG;IACH,IAAI,IAAI,iBAAiB,GAAG,IAAI;IAiBhC;;;;;;;;;;;;;;;;;;;;OAoBG;IACI,yBAAyB,CAAC,MAAM,EAAE,iBAAiB,GAAG,iBAAiB;IAsF9E,OAAO,CAAC,WAAW;IAsBnB;;;;;;;OAOG;IACH,OAAO,CAAC,yBAAyB;IAuCjC,OAAO,CAAC,uBAAuB;IAW/B;;;;;;;OAOG;IACH,OAAO,CAAC,YAAY;IAOpB;;;;;;;;;;OAUG;IACH,OAAO,CAAC,WAAW;IASnB;;;;;;;;;;;;;;;;;;OAkBG;IACH,qBAAqB,CAAC,MAAM,EAAE,iBAAiB,GAAG,mBAAmB;CAkBrE"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"config/ConfigLoader.js","sources":["../../src/config/ConfigLoader.ts"],"sourcesContent":["/**\n * Configuration file loading with environment variable override support.\n *\n * This module provides the `ConfigLoader` class which handles loading configuration\n * from YAML and JSON files in standard locations, with automatic environment variable\n * overrides for all settings.\n *\n * @module config\n */\n\nimport { existsSync, readFileSync } from 'node:fs';\nimport { homedir } from 'node:os';\nimport { join } from 'node:path';\nimport { parse as parseYaml } from 'yaml';\nimport * as v from 'valibot';\nimport type { PersistenceConfig } from '../contracts/PersistenceBackend.js';\nimport { ConfigurationError, getErrorMessage } from '../errors.js';\nimport type { FeatureFlags } from '../contracts/features.js';\nimport type { ServerConfigOptions } from '../ServerConfig.js';\n\n/**\n * Lenient runtime schema for config files. Only validates top-level shape;\n * unknown extra fields are preserved by Valibot's default object behavior\n * being strict is avoided by using `v.looseObject`. All fields are optional.\n */\nconst ConfigFileOptionsSchema = v.looseObject({\n\tmaxHistorySize: v.optional(v.number()),\n\tmaxBranches: v.optional(v.number()),\n\tmaxBranchSize: v.optional(v.number()),\n\tlogLevel: v.optional(v.picklist(['debug', 'info', 'warn', 'error'])),\n\tprettyLog: v.optional(v.boolean()),\n\tskillDirs: v.optional(v.array(v.string())),\n\ttoolDirs: v.optional(v.array(v.string())),\n\tdiscoveryCache: v.optional(\n\t\tv.looseObject({\n\t\t\tttl: v.optional(v.number()),\n\t\t\tmaxSize: v.optional(v.number()),\n\t\t})\n\t),\n\tpersistence: v.optional(v.looseObject({})),\n\tpersistenceBufferSize: v.optional(v.number()),\n\tpersistenceFlushInterval: v.optional(v.number()),\n\tpersistenceMaxRetries: v.optional(v.number()),\n\tfeatures: v.optional(v.looseObject({})),\n\ttoolInterleaveTtlMs: v.optional(v.number()),\n\ttoolInterleaveSweepMs: v.optional(v.number()),\n\tmaxSessionsPerOwner: v.optional(v.number()),\n});\n\ntype Mutable<T> = { -readonly [K in keyof T]: T[K] };\n\n/**\n * Configuration options loaded from config files.\n *\n * These options represent the structure of configuration files (JSON or YAML)\n * that can be loaded from standard locations. All values can be overridden\n * by environment variables.\n *\n * @example\n * ```yaml\n * # .claude/config.yaml\n * maxHistorySize: 500\n * maxBranches: 25\n * logLevel: debug\n * prettyLog: true\n * skillDirs:\n * - ./custom-skills\n * toolDirs:\n * - ./custom-tools\n * discoveryCache:\n * ttl: 600000\n * maxSize: 200\n * persistence:\n * enabled: true\n * backend: sqlite\n * options:\n * dbPath: ./data/history.db\n * ```\n */\nexport interface ConfigFileOptions {\n\t/**\n\t * Maximum number of thoughts to keep in history.\n\t * Can be overridden by `TRACELATTICE_MAX_HISTORY_SIZE` environment variable.\n\t */\n\treadonly maxHistorySize?: number;\n\n\t/**\n\t * Maximum number of branches to maintain.\n\t * Can be overridden by `TRACELATTICE_MAX_BRANCHES` environment variable.\n\t */\n\treadonly maxBranches?: number;\n\n\t/**\n\t * Maximum size of each branch.\n\t * Can be overridden by `TRACELATTICE_MAX_BRANCH_SIZE` environment variable.\n\t */\n\treadonly maxBranchSize?: number;\n\n\t/**\n\t * Logging level for the application.\n\t * Can be overridden by `TRACELATTICE_LOG_LEVEL` environment variable.\n\t */\n\treadonly logLevel?: 'debug' | 'info' | 'warn' | 'error';\n\n\t/**\n\t * Whether to enable pretty (formatted) logging output.\n\t * Can be overridden by `TRACELATTICE_PRETTY_LOG` environment variable (set to \"false\" to disable).\n\t */\n\treadonly prettyLog?: boolean;\n\n\t/**\n\t * Directory paths to search for skills.\n\t * Can be overridden by `TRACELATTICE_SKILL_DIRS` environment variable (colon-separated).\n\t */\n\treadonly skillDirs?: string[];\n\n\t/**\n\t * Directory paths to search for tools.\n\t * Can be overridden by `TRACELATTICE_TOOL_DIRS` environment variable (colon-separated).\n\t */\n\treadonly toolDirs?: string[];\n\n\t/**\n\t * Discovery cache configuration.\n\t * Can be overridden by `TRACELATTICE_DISCOVERY_CACHE_TTL` and\n\t * `TRACELATTICE_DISCOVERY_CACHE_MAX_SIZE` environment variables.\n\t */\n\treadonly discoveryCache?: {\n\t\t/**\n\t\t * Time-to-live for cache entries in milliseconds.\n\t\t * Environment variable `TRACELATTICE_DISCOVERY_CACHE_TTL` accepts seconds.\n\t\t */\n\t\treadonly ttl?: number;\n\t\t/**\n\t\t * Maximum number of entries in the cache.\n\t\t */\n\t\treadonly maxSize?: number;\n\t};\n\n\t/**\n\t * Persistence configuration for storing history and state.\n\t */\n\treadonly persistence?: PersistenceConfig;\n\n\treadonly persistenceBufferSize?: number;\n\n\treadonly persistenceFlushInterval?: number;\n\n\treadonly persistenceMaxRetries?: number;\n\n\t/**\n\t * Feature flag overrides. Each field can be set independently.\n\t * Can be overridden by `TRACELATTICE_FEATURES_*` environment variables.\n\t */\n\treadonly features?: Partial<FeatureFlags>;\n\n\t/**\n\t * TTL in milliseconds for suspended tool-interleave entries.\n\t * Can be overridden by `TRACELATTICE_TOOL_INTERLEAVE_TTL_MS` environment variable.\n\t */\n\treadonly toolInterleaveTtlMs?: number;\n\n\t/**\n\t * Sweep interval in milliseconds for SuspensionStore expiration cleanup.\n\t * Can be overridden by `TRACELATTICE_TOOL_INTERLEAVE_SWEEP_MS` environment variable.\n\t */\n\treadonly toolInterleaveSweepMs?: number;\n\n\t/**\n\t * Maximum sessions per owner. Per-owner LRU bucket prevents one user from\n\t * consuming all session slots.\n\t * Can be overridden by `TRACELATTICE_SESSION_MAX_PER_OWNER` environment variable.\n\t */\n\treadonly maxSessionsPerOwner?: number;\n}\n\n/**\n * Loads configuration from files with environment variable overrides.\n *\n * This class searches for configuration files in standard locations and applies\n * environment variable overrides. Files are searched in priority order, with the\n * first match being used. Environment variables always take precedence over file values.\n *\n * @remarks\n * **Config File Search Order (priority):**\n * 1. Custom path (if provided to constructor)\n * 2. `.claude/config.json` (project-local)\n * 3. `.claude/config.yaml` (project-local)\n * 4. `.claude/config.yml` (project-local)\n * 5. `~/.claude/config.json` (user-global)\n * 6. `~/.claude/config.yaml` (user-global)\n * 7. `~/.claude/config.yml` (user-global)\n *\n * **Environment Variable Overrides:**\n * | Variable | Type | Description |\n * |----------|------|-------------|\n * | `TRACELATTICE_MAX_HISTORY_SIZE` | number | Max thoughts in history |\n * | `TRACELATTICE_MAX_BRANCHES` | number | Max number of branches |\n * | `TRACELATTICE_MAX_BRANCH_SIZE` | number | Max size of each branch |\n * | `TRACELATTICE_LOG_LEVEL` | string | Logging level (debug/info/warn/error) |\n * | `TRACELATTICE_PRETTY_LOG` | string | \"false\" to disable pretty logging |\n * | `TRACELATTICE_SKILL_DIRS` | string | Colon-separated directory paths |\n * | `TRACELATTICE_TOOL_DIRS` | string | Colon-separated directory paths |\n * | `TRACELATTICE_DISCOVERY_CACHE_TTL` | number | TTL in seconds (converted to ms) |\n * | `TRACELATTICE_DISCOVERY_CACHE_MAX_SIZE` | number | Max cache entries |\n *\n * @example\n * ```typescript\n * // Use default search paths\n * const loader1 = new ConfigLoader();\n * const config1 = loader1.load();\n *\n * // Use custom config path\n * const loader2 = new ConfigLoader('./my-config.yaml');\n * const config2 = loader2.load();\n *\n * // Convert to ServerConfig options\n * const serverOptions = loader2.toServerConfigOptions(config2);\n * ```\n */\nexport class ConfigLoader {\n\t/** Array of config file paths to search, in priority order. */\n\tprivate _configPaths: string[];\n\n\t/**\n\t * Creates a new ConfigLoader instance.\n\t *\n\t * @param customPath - Optional custom config file path. If provided, only this path will be checked.\n\t *\n\t * @example\n\t * ```typescript\n\t * // Use default search paths\n\t * const loader1 = new ConfigLoader();\n\t *\n\t * // Use a specific config file\n\t * const loader2 = new ConfigLoader('./custom-config.json');\n\t * ```\n\t */\n\tconstructor(customPath?: string) {\n\t\tconst configuredPath = customPath ?? process.env.TRACELATTICE_CONFIG;\n\t\tthis._configPaths = configuredPath\n\t\t\t? [configuredPath]\n\t\t\t: [\n\t\t\t\t\t'.claude/config.json',\n\t\t\t\t\t'.claude/config.yaml',\n\t\t\t\t\t'.claude/config.yml',\n\t\t\t\t\tjoin(homedir(), '.claude/config.json'),\n\t\t\t\t\tjoin(homedir(), '.claude/config.yaml'),\n\t\t\t\t\tjoin(homedir(), '.claude/config.yml'),\n\t\t\t\t];\n\t}\n\n\t/**\n\t * Loads configuration from files and applies environment overrides.\n\t *\n\t * Searches for config files in the configured paths (in priority order),\n\t * parses the first match, and applies environment variable overrides.\n\t * Returns null if no config file is found and no environment overrides are set.\n\t *\n\t * @returns The loaded configuration with environment overrides applied, or null if no config found\n\t *\n\t * @example\n\t * ```typescript\n\t * const loader = new ConfigLoader();\n\t * const config = loader.load();\n\t *\n\t * if (config) {\n\t * console.log('Max history size:', config.maxHistorySize);\n\t * console.log('Log level:', config.logLevel);\n\t * }\n\t * ```\n\t */\n\tload(): ConfigFileOptions | null {\n\t\tlet config: ConfigFileOptions | null = null;\n\n\t\tfor (const configPath of this._configPaths) {\n\t\t\tif (existsSync(configPath)) {\n\t\t\t\ttry {\n\t\t\t\t\tconfig = this.parseConfig(configPath);\n\t\t\t\t\tbreak;\n\t\t\t\t} catch (error) {\n\t\t\t\t\tconsole.error(`Failed to load config from ${configPath}:`, getErrorMessage(error));\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\n\t\treturn this.applyEnvironmentOverrides(config || {});\n\t}\n\n\t/**\n\t * Applies environment variable overrides to the configuration.\n\t *\n\t * Environment variables take precedence over file-based configuration.\n\t * Supported environment variables:\n\t * - `TRACELATTICE_MAX_HISTORY_SIZE`, `TRACELATTICE_MAX_BRANCHES`,\n\t * `TRACELATTICE_MAX_BRANCH_SIZE` (numbers)\n\t * - `TRACELATTICE_LOG_LEVEL` (debug/info/warn/error)\n\t * - `TRACELATTICE_PRETTY_LOG` (\"false\" to disable)\n\t * - `TRACELATTICE_SKILL_DIRS` (colon-separated paths)\n\t * - `TRACELATTICE_TOOL_DIRS` (colon-separated paths)\n\t * - `TRACELATTICE_DISCOVERY_CACHE_TTL` (in seconds, converted to ms)\n\t * - `TRACELATTICE_DISCOVERY_CACHE_MAX_SIZE` (number)\n\t *\n\t * @param config - The configuration to apply overrides to\n\t * @returns A new configuration object with environment overrides applied\n\t */\n\tpublic applyEnvironmentOverrides(config: ConfigFileOptions): ConfigFileOptions {\n\t\tconst result = this.cloneConfig(config);\n\n\t\tif (process.env.TRACELATTICE_MAX_HISTORY_SIZE !== undefined) {\n\t\t\tresult.maxHistorySize = this.parseEnvironmentInteger(\n\t\t\t\t'TRACELATTICE_MAX_HISTORY_SIZE',\n\t\t\t\tprocess.env.TRACELATTICE_MAX_HISTORY_SIZE\n\t\t\t);\n\t\t}\n\t\tif (process.env.TRACELATTICE_MAX_BRANCHES !== undefined) {\n\t\t\tresult.maxBranches = this.parseEnvironmentInteger(\n\t\t\t\t'TRACELATTICE_MAX_BRANCHES',\n\t\t\t\tprocess.env.TRACELATTICE_MAX_BRANCHES\n\t\t\t);\n\t\t}\n\t\tif (process.env.TRACELATTICE_MAX_BRANCH_SIZE !== undefined) {\n\t\t\tresult.maxBranchSize = this.parseEnvironmentInteger(\n\t\t\t\t'TRACELATTICE_MAX_BRANCH_SIZE',\n\t\t\t\tprocess.env.TRACELATTICE_MAX_BRANCH_SIZE\n\t\t\t);\n\t\t}\n\t\tif (\n\t\t\tprocess.env.TRACELATTICE_LOG_LEVEL &&\n\t\t\t['debug', 'info', 'warn', 'error'].includes(process.env.TRACELATTICE_LOG_LEVEL)\n\t\t) {\n\t\t\tresult.logLevel = process.env.TRACELATTICE_LOG_LEVEL as 'debug' | 'info' | 'warn' | 'error';\n\t\t}\n\t\tif (process.env.TRACELATTICE_PRETTY_LOG === 'false') {\n\t\t\tresult.prettyLog = false;\n\t\t}\n\t\tif (process.env.TRACELATTICE_SKILL_DIRS !== undefined) {\n\t\t\tresult.skillDirs =\n\t\t\t\tprocess.env.TRACELATTICE_SKILL_DIRS === ''\n\t\t\t\t\t? []\n\t\t\t\t\t: process.env.TRACELATTICE_SKILL_DIRS.split(':');\n\t\t}\n\t\tif (process.env.TRACELATTICE_TOOL_DIRS !== undefined) {\n\t\t\tresult.toolDirs =\n\t\t\t\tprocess.env.TRACELATTICE_TOOL_DIRS === ''\n\t\t\t\t\t? []\n\t\t\t\t\t: process.env.TRACELATTICE_TOOL_DIRS.split(':');\n\t\t}\n\t\tif (process.env.TRACELATTICE_DISCOVERY_CACHE_TTL !== undefined) {\n\t\t\tconst seconds = this.parseEnvironmentInteger(\n\t\t\t\t'TRACELATTICE_DISCOVERY_CACHE_TTL',\n\t\t\t\tprocess.env.TRACELATTICE_DISCOVERY_CACHE_TTL\n\t\t\t);\n\t\t\tconst ttl = seconds * 1000;\n\t\t\tif (!Number.isSafeInteger(ttl)) {\n\t\t\t\tthrow new ConfigurationError(\n\t\t\t\t\t'TRACELATTICE_DISCOVERY_CACHE_TTL exceeds the safe integer range'\n\t\t\t\t);\n\t\t\t}\n\t\t\tresult.discoveryCache = { ...result.discoveryCache, ttl };\n\t\t}\n\t\tif (process.env.TRACELATTICE_DISCOVERY_CACHE_MAX_SIZE !== undefined) {\n\t\t\tconst maxSize = this.parseEnvironmentInteger(\n\t\t\t\t'TRACELATTICE_DISCOVERY_CACHE_MAX_SIZE',\n\t\t\t\tprocess.env.TRACELATTICE_DISCOVERY_CACHE_MAX_SIZE\n\t\t\t);\n\t\t\tresult.discoveryCache = { ...result.discoveryCache, maxSize };\n\t\t}\n\t\tif (process.env.TRACELATTICE_TOOL_INTERLEAVE_TTL_MS !== undefined) {\n\t\t\tresult.toolInterleaveTtlMs = this.parseEnvironmentInteger(\n\t\t\t\t'TRACELATTICE_TOOL_INTERLEAVE_TTL_MS',\n\t\t\t\tprocess.env.TRACELATTICE_TOOL_INTERLEAVE_TTL_MS\n\t\t\t);\n\t\t}\n\t\tif (process.env.TRACELATTICE_TOOL_INTERLEAVE_SWEEP_MS !== undefined) {\n\t\t\tresult.toolInterleaveSweepMs = this.parseEnvironmentInteger(\n\t\t\t\t'TRACELATTICE_TOOL_INTERLEAVE_SWEEP_MS',\n\t\t\t\tprocess.env.TRACELATTICE_TOOL_INTERLEAVE_SWEEP_MS\n\t\t\t);\n\t\t}\n\t\tif (process.env.TRACELATTICE_SESSION_MAX_PER_OWNER !== undefined) {\n\t\t\tresult.maxSessionsPerOwner = this.parseEnvironmentInteger(\n\t\t\t\t'TRACELATTICE_SESSION_MAX_PER_OWNER',\n\t\t\t\tprocess.env.TRACELATTICE_SESSION_MAX_PER_OWNER\n\t\t\t);\n\t\t}\n\n\t\tthis.applyFeatureFlagOverrides(result);\n\n\t\treturn result;\n\t}\n\n\tprivate cloneConfig(config: ConfigFileOptions): Mutable<ConfigFileOptions> {\n\t\treturn {\n\t\t\t...config,\n\t\t\t...(config.skillDirs === undefined ? {} : { skillDirs: [...config.skillDirs] }),\n\t\t\t...(config.toolDirs === undefined ? {} : { toolDirs: [...config.toolDirs] }),\n\t\t\t...(config.discoveryCache === undefined\n\t\t\t\t? {}\n\t\t\t\t: { discoveryCache: { ...config.discoveryCache } }),\n\t\t\t...(config.persistence === undefined\n\t\t\t\t? {}\n\t\t\t\t: {\n\t\t\t\t\t\tpersistence: {\n\t\t\t\t\t\t\t...config.persistence,\n\t\t\t\t\t\t\t...(config.persistence.options === undefined\n\t\t\t\t\t\t\t\t? {}\n\t\t\t\t\t\t\t\t: { options: { ...config.persistence.options } }),\n\t\t\t\t\t\t},\n\t\t\t\t\t}),\n\t\t\t...(config.features === undefined ? {} : { features: { ...config.features } }),\n\t\t};\n\t}\n\n\t/**\n\t * Applies TRACELATTICE_FEATURES_* environment variable overrides for feature flags.\n\t * Booleans accept 'true'/'false'/'1'/'0' (case-insensitive).\n\t * Invalid reasoningStrategy values are rejected.\n\t *\n\t * @param result - Configuration object to mutate with feature flag overrides\n\t * @private\n\t */\n\tprivate applyFeatureFlagOverrides(result: Mutable<ConfigFileOptions>): void {\n\t\tconst boolMap: Record<string, Exclude<keyof FeatureFlags, 'reasoningStrategy'>> = {\n\t\t\tTRACELATTICE_FEATURES_DAG_EDGES: 'dagEdges',\n\t\t\tTRACELATTICE_FEATURES_CALIBRATION: 'calibration',\n\t\t\tTRACELATTICE_FEATURES_COMPRESSION: 'compression',\n\t\t\tTRACELATTICE_FEATURES_TOOL_INTERLEAVE: 'toolInterleave',\n\t\t\tTRACELATTICE_FEATURES_NEW_THOUGHT_TYPES: 'newThoughtTypes',\n\t\t\tTRACELATTICE_FEATURES_OUTCOME_RECORDING: 'outcomeRecording',\n\t\t};\n\t\tfor (const [envVar, key] of Object.entries(boolMap)) {\n\t\t\tconst raw = process.env[envVar];\n\t\t\tif (raw === undefined) continue;\n\t\t\tconst parsed = this.parseBoolean(raw);\n\t\t\tif (parsed === undefined) {\n\t\t\t\tconsole.warn(\n\t\t\t\t\t`Invalid boolean value for ${envVar}: \"${raw}\" (expected true/false/1/0). Ignoring.`\n\t\t\t\t);\n\t\t\t\tcontinue;\n\t\t\t}\n\t\t\tconst features: { -readonly [K in keyof FeatureFlags]?: FeatureFlags[K] } =\n\t\t\t\tresult.features ?? {};\n\t\t\tfeatures[key] = parsed;\n\t\t\tresult.features = features;\n\t\t}\n\n\t\tconst strategyRaw = process.env.TRACELATTICE_FEATURES_REASONING_STRATEGY;\n\t\tif (strategyRaw !== undefined) {\n\t\t\tif (strategyRaw !== 'sequential' && strategyRaw !== 'tot') {\n\t\t\t\tthrow new ConfigurationError(\n\t\t\t\t\t`TRACELATTICE_FEATURES_REASONING_STRATEGY must be one of sequential, tot, got ${strategyRaw}`\n\t\t\t\t);\n\t\t\t}\n\t\t\tconst features: { -readonly [K in keyof FeatureFlags]?: FeatureFlags[K] } =\n\t\t\t\tresult.features ?? {};\n\t\t\tfeatures.reasoningStrategy = strategyRaw;\n\t\t\tresult.features = features;\n\t\t}\n\t}\n\n\tprivate parseEnvironmentInteger(environmentName: string, raw: string): number {\n\t\tif (!/^(0|[1-9]\\d*)$/.test(raw)) {\n\t\t\tthrow new ConfigurationError(`${environmentName} must be an integer, got ${raw}`);\n\t\t}\n\t\tconst parsed = Number(raw);\n\t\tif (!Number.isSafeInteger(parsed)) {\n\t\t\tthrow new ConfigurationError(`${environmentName} must be a safe integer, got ${raw}`);\n\t\t}\n\t\treturn parsed;\n\t}\n\n\t/**\n\t * Parses a boolean from an environment variable string.\n\t * Accepts 'true'/'false'/'1'/'0' case-insensitively.\n\t *\n\t * @param raw - Raw environment variable string\n\t * @returns Parsed boolean, or undefined if the value is invalid\n\t * @private\n\t */\n\tprivate parseBoolean(raw: string): boolean | undefined {\n\t\tconst v = raw.trim().toLowerCase();\n\t\tif (v === 'true' || v === '1') return true;\n\t\tif (v === 'false' || v === '0') return false;\n\t\treturn undefined;\n\t}\n\n\t/**\n\t * Parses a configuration file (JSON or YAML).\n\t *\n\t * Detects the file type by extension and uses the appropriate parser.\n\t * Supports `.json`, `.yaml`, and `.yml` file extensions.\n\t *\n\t * @param filePath - Path to the configuration file to parse\n\t * @returns The parsed configuration object\n\t * @throws {Error} If the file cannot be parsed\n\t * @private\n\t */\n\tprivate parseConfig(filePath: string): ConfigFileOptions {\n\t\tconst content = readFileSync(filePath, 'utf-8');\n\t\tconst ext = filePath.split('.').pop()?.toLowerCase();\n\n\t\tconst raw: unknown = ext === 'yaml' || ext === 'yml' ? parseYaml(content) : JSON.parse(content);\n\n\t\treturn v.parse(ConfigFileOptionsSchema, raw) as ConfigFileOptions;\n\t}\n\n\t/**\n\t * Converts file-based configuration to ServerConfig options.\n\t *\n\t * This is a convenience method for extracting the ServerConfig-relevant\n\t * options from a file-based configuration.\n\t *\n\t * @param config - The configuration to convert\n\t * @returns An object with ServerConfig-compatible options\n\t *\n\t * @example\n\t * ```typescript\n\t * const loader = new ConfigLoader();\n\t * const config = loader.load();\n\t * if (config) {\n\t * const serverOpts = loader.toServerConfigOptions(config);\n\t * const serverConfig = new ServerConfig(serverOpts);\n\t * }\n\t * ```\n\t */\n\ttoServerConfigOptions(config: ConfigFileOptions): ServerConfigOptions {\n\t\treturn {\n\t\t\tmaxHistorySize: config.maxHistorySize,\n\t\t\tmaxBranches: config.maxBranches,\n\t\t\tmaxBranchSize: config.maxBranchSize,\n\t\t\tskillDirs: config.skillDirs,\n\t\t\ttoolDirs: config.toolDirs,\n\t\t\tdiscoveryCache: config.discoveryCache,\n\t\t\tpersistence: config.persistence,\n\t\t\tpersistenceBufferSize: config.persistenceBufferSize,\n\t\t\tpersistenceFlushInterval: config.persistenceFlushInterval,\n\t\t\tpersistenceMaxRetries: config.persistenceMaxRetries,\n\t\t\tfeatures: config.features,\n\t\t\ttoolInterleaveTtlMs: config.toolInterleaveTtlMs,\n\t\t\ttoolInterleaveSweepMs: config.toolInterleaveSweepMs,\n\t\t\tmaxSessionsPerOwner: config.maxSessionsPerOwner,\n\t\t};\n\t}\n}\n"],"names":["ConfigFileOptionsSchema","v","ConfigLoader","customPath","configuredPath","process","join","homedir","config","configPath","existsSync","error","console","getErrorMessage","result","undefined","seconds","ttl","Number","ConfigurationError","maxSize","boolMap","envVar","key","Object","raw","parsed","features","strategyRaw","environmentName","filePath","content","readFileSync","ext","parseYaml","JSON"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"config/ConfigLoader.js","sources":["../../src/config/ConfigLoader.ts"],"sourcesContent":["/**\n * Configuration file loading with environment variable override support.\n *\n * This module provides the `ConfigLoader` class which handles loading configuration\n * from YAML and JSON files in standard locations, with automatic environment variable\n * overrides for supported settings. Persistence buffer, flush, and retry settings are file-only.\n *\n * @module config\n */\n\nimport { existsSync, readFileSync } from 'node:fs';\nimport { homedir } from 'node:os';\nimport { join } from 'node:path';\nimport { parse as parseYaml } from 'yaml';\nimport * as v from 'valibot';\nimport type { PersistenceConfig } from '../contracts/PersistenceBackend.js';\nimport { ConfigurationError, getErrorMessage } from '../errors.js';\nimport type { FeatureFlags } from '../contracts/features.js';\nimport type { ServerConfigOptions } from '../ServerConfig.js';\n\n/**\n * Lenient runtime schema for config files. Only validates top-level shape;\n * unknown extra fields are preserved by Valibot's default object behavior\n * being strict is avoided by using `v.looseObject`. All fields are optional.\n */\nconst ConfigFileOptionsSchema = v.looseObject({\n\tmaxHistorySize: v.optional(v.number()),\n\tmaxBranches: v.optional(v.number()),\n\tmaxBranchSize: v.optional(v.number()),\n\tlogLevel: v.optional(v.picklist(['debug', 'info', 'warn', 'error'])),\n\tprettyLog: v.optional(v.boolean()),\n\tskillDirs: v.optional(v.array(v.string())),\n\ttoolDirs: v.optional(v.array(v.string())),\n\tdiscoveryCache: v.optional(\n\t\tv.looseObject({\n\t\t\tttl: v.optional(v.number()),\n\t\t\tmaxSize: v.optional(v.number()),\n\t\t})\n\t),\n\tpersistence: v.optional(v.looseObject({})),\n\tpersistenceBufferSize: v.optional(v.number()),\n\tpersistenceFlushInterval: v.optional(v.number()),\n\tpersistenceMaxRetries: v.optional(v.number()),\n\tfeatures: v.optional(v.looseObject({})),\n\ttoolInterleaveTtlMs: v.optional(v.number()),\n\ttoolInterleaveSweepMs: v.optional(v.number()),\n\tmaxSessionsPerOwner: v.optional(v.number()),\n});\n\ntype Mutable<T> = { -readonly [K in keyof T]: T[K] };\n\n/**\n * Configuration options loaded from config files.\n *\n * These options represent the structure of configuration files (JSON or YAML)\n * that can be loaded from standard locations. Only supported fields have\n * environment overrides; persistence buffer, flush, and retry settings are file-only.\n *\n * @example\n * ```yaml\n * # .claude/config.yaml\n * maxHistorySize: 500\n * maxBranches: 25\n * logLevel: debug\n * prettyLog: true\n * skillDirs:\n * - ./custom-skills\n * toolDirs:\n * - ./custom-tools\n * discoveryCache:\n * ttl: 600000\n * maxSize: 200\n * persistence:\n * enabled: true\n * backend: sqlite\n * options:\n * dbPath: ./data/history.db\n * ```\n */\nexport interface ConfigFileOptions {\n\t/**\n\t * Maximum number of thoughts to keep in history.\n\t * Can be overridden by `TRACELATTICE_MAX_HISTORY_SIZE` environment variable.\n\t */\n\treadonly maxHistorySize?: number;\n\n\t/**\n\t * Maximum number of branches to maintain.\n\t * Can be overridden by `TRACELATTICE_MAX_BRANCHES` environment variable.\n\t */\n\treadonly maxBranches?: number;\n\n\t/**\n\t * Maximum size of each branch.\n\t * Can be overridden by `TRACELATTICE_MAX_BRANCH_SIZE` environment variable.\n\t */\n\treadonly maxBranchSize?: number;\n\n\t/**\n\t * Logging level for the application.\n\t * Can be overridden by `TRACELATTICE_LOG_LEVEL` environment variable.\n\t */\n\treadonly logLevel?: 'debug' | 'info' | 'warn' | 'error';\n\n\t/**\n\t * Whether to enable pretty (formatted) logging output.\n\t * Can be overridden by `TRACELATTICE_PRETTY_LOG` environment variable (set to \"false\" to disable).\n\t */\n\treadonly prettyLog?: boolean;\n\n\t/**\n\t * Directory paths to search for skills.\n\t * Can be overridden by `TRACELATTICE_SKILL_DIRS` environment variable (colon-separated).\n\t */\n\treadonly skillDirs?: string[];\n\n\t/**\n\t * Directory paths to search for tools.\n\t * Can be overridden by `TRACELATTICE_TOOL_DIRS` environment variable (colon-separated).\n\t */\n\treadonly toolDirs?: string[];\n\n\t/**\n\t * Discovery cache configuration.\n\t * Can be overridden by `TRACELATTICE_DISCOVERY_CACHE_TTL` and\n\t * `TRACELATTICE_DISCOVERY_CACHE_MAX_SIZE` environment variables.\n\t */\n\treadonly discoveryCache?: {\n\t\t/**\n\t\t * Time-to-live for cache entries in milliseconds.\n\t\t * Environment variable `TRACELATTICE_DISCOVERY_CACHE_TTL` accepts seconds.\n\t\t */\n\t\treadonly ttl?: number;\n\t\t/**\n\t\t * Maximum number of entries in the cache.\n\t\t */\n\t\treadonly maxSize?: number;\n\t};\n\n\t/**\n\t * Persistence configuration for storing history and state.\n\t */\n\treadonly persistence?: PersistenceConfig;\n\n\t/** Maximum buffered thoughts before flushing; file-only (default 100 in ServerConfig). */\n\treadonly persistenceBufferSize?: number;\n\n\t/** Periodic flush interval in milliseconds; file-only (default 1000 in ServerConfig). */\n\treadonly persistenceFlushInterval?: number;\n\n\t/** Maximum flush retries; file-only (default 3 in ServerConfig). */\n\treadonly persistenceMaxRetries?: number;\n\n\t/**\n\t * Feature flag overrides. Each field can be set independently.\n\t * Can be overridden by `TRACELATTICE_FEATURES_*` environment variables.\n\t */\n\treadonly features?: Partial<FeatureFlags>;\n\n\t/**\n\t * TTL in milliseconds for suspended tool-interleave entries.\n\t * Can be overridden by `TRACELATTICE_TOOL_INTERLEAVE_TTL_MS` environment variable.\n\t */\n\treadonly toolInterleaveTtlMs?: number;\n\n\t/**\n\t * Sweep interval in milliseconds for SuspensionStore expiration cleanup.\n\t * Can be overridden by `TRACELATTICE_TOOL_INTERLEAVE_SWEEP_MS` environment variable.\n\t */\n\treadonly toolInterleaveSweepMs?: number;\n\n\t/**\n\t * Maximum sessions per owner. Per-owner LRU bucket prevents one user from\n\t * consuming all session slots.\n\t * Can be overridden by `TRACELATTICE_SESSION_MAX_PER_OWNER` environment variable.\n\t */\n\treadonly maxSessionsPerOwner?: number;\n}\n\n/**\n * Loads configuration from files with environment variable overrides.\n *\n * This class searches for configuration files in standard locations and applies\n * environment variable overrides. Files are searched in priority order, with the\n * first valid match being used. Supported environment variables take precedence over file values.\n *\n * @remarks\n * **Config File Search Order (priority):**\n * 1. Custom path or `TRACELATTICE_CONFIG` (if present, replaces the default search list)\n * 2. `.claude/config.json` (project-local)\n * 3. `.claude/config.yaml` (project-local)\n * 4. `.claude/config.yml` (project-local)\n * 5. `~/.claude/config.json` (user-global)\n * 6. `~/.claude/config.yaml` (user-global)\n * 7. `~/.claude/config.yml` (user-global)\n *\n * **Environment Variable Overrides:**\n * | Variable | Type | Description |\n * |----------|------|-------------|\n * | `TRACELATTICE_MAX_HISTORY_SIZE` | number | Max thoughts in history |\n * | `TRACELATTICE_MAX_BRANCHES` | number | Max number of branches |\n * | `TRACELATTICE_MAX_BRANCH_SIZE` | number | Max size of each branch |\n * | `TRACELATTICE_LOG_LEVEL` | string | Logging level (debug/info/warn/error) |\n * | `TRACELATTICE_PRETTY_LOG` | string | \"false\" to disable pretty logging |\n * | `TRACELATTICE_SKILL_DIRS` | string | Colon-separated directory paths |\n * | `TRACELATTICE_TOOL_DIRS` | string | Colon-separated directory paths |\n * | `TRACELATTICE_DISCOVERY_CACHE_TTL` | number | TTL in seconds (converted to ms) |\n * | `TRACELATTICE_DISCOVERY_CACHE_MAX_SIZE` | number | Max cache entries |\n * | `TRACELATTICE_TOOL_INTERLEAVE_TTL_MS` / `TRACELATTICE_TOOL_INTERLEAVE_SWEEP_MS` | number | Milliseconds |\n * | `TRACELATTICE_SESSION_MAX_PER_OWNER` | number | Max sessions per owner |\n * | `TRACELATTICE_FEATURES_*` | boolean or strategy | Feature toggles or `sequential`/`tot` |\n *\n * Persistence buffer size, flush interval (milliseconds), and retries are file-only.\n *\n * @example\n * ```typescript\n * // Use default search paths\n * const loader1 = new ConfigLoader();\n * const config1 = loader1.load();\n *\n * // Use custom config path\n * const loader2 = new ConfigLoader('./my-config.yaml');\n * const config2 = loader2.load();\n *\n * // Convert to ServerConfig options\n * const serverOptions = loader2.toServerConfigOptions(config2);\n * ```\n */\nexport class ConfigLoader {\n\t/** Array of config file paths to search, in priority order. */\n\tprivate _configPaths: string[];\n\n\t/**\n\t * Creates a new ConfigLoader instance.\n\t *\n\t * @param customPath - Optional custom config file path. If provided, only this path will be checked.\n\t *\n\t * @example\n\t * ```typescript\n\t * // Use default search paths\n\t * const loader1 = new ConfigLoader();\n\t *\n\t * // Use a specific config file\n\t * const loader2 = new ConfigLoader('./custom-config.json');\n\t * ```\n\t */\n\tconstructor(customPath?: string) {\n\t\tconst configuredPath = customPath ?? process.env.TRACELATTICE_CONFIG;\n\t\tthis._configPaths = configuredPath\n\t\t\t? [configuredPath]\n\t\t\t: [\n\t\t\t\t\t'.claude/config.json',\n\t\t\t\t\t'.claude/config.yaml',\n\t\t\t\t\t'.claude/config.yml',\n\t\t\t\t\tjoin(homedir(), '.claude/config.json'),\n\t\t\t\t\tjoin(homedir(), '.claude/config.yaml'),\n\t\t\t\t\tjoin(homedir(), '.claude/config.yml'),\n\t\t\t\t];\n\t}\n\n\t/**\n\t * Loads configuration from files and applies environment overrides.\n\t *\n\t * Searches for config files in the configured paths (in priority order),\n\t * parses the first match, and applies environment variable overrides.\n\t * A malformed file is logged and skipped. With no valid file, applies environment\n\t * overrides to an empty object (the declared nullable return type does not return null).\n\t *\n\t * @returns The loaded configuration with environment overrides applied, or an empty/overlaid object\n\t *\n\t * @example\n\t * ```typescript\n\t * const loader = new ConfigLoader();\n\t * const config = loader.load();\n\t *\n\t * if (config) {\n\t * console.log('Max history size:', config.maxHistorySize);\n\t * console.log('Log level:', config.logLevel);\n\t * }\n\t * ```\n\t */\n\tload(): ConfigFileOptions | null {\n\t\tlet config: ConfigFileOptions | null = null;\n\n\t\tfor (const configPath of this._configPaths) {\n\t\t\tif (existsSync(configPath)) {\n\t\t\t\ttry {\n\t\t\t\t\tconfig = this.parseConfig(configPath);\n\t\t\t\t\tbreak;\n\t\t\t\t} catch (error) {\n\t\t\t\t\tconsole.error(`Failed to load config from ${configPath}:`, getErrorMessage(error));\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\n\t\treturn this.applyEnvironmentOverrides(config || {});\n\t}\n\n\t/**\n\t * Applies environment variable overrides to the configuration.\n\t *\n\t * Environment variables take precedence over file-based configuration.\n\t * Supported environment variables:\n\t * - `TRACELATTICE_MAX_HISTORY_SIZE`, `TRACELATTICE_MAX_BRANCHES`,\n\t * `TRACELATTICE_MAX_BRANCH_SIZE` (numbers)\n\t * - `TRACELATTICE_LOG_LEVEL` (debug/info/warn/error)\n\t * - `TRACELATTICE_PRETTY_LOG` (\"false\" to disable)\n\t * - `TRACELATTICE_SKILL_DIRS` (colon-separated paths)\n\t * - `TRACELATTICE_TOOL_DIRS` (colon-separated paths)\n\t * - `TRACELATTICE_DISCOVERY_CACHE_TTL` (in seconds, converted to ms)\n\t * - `TRACELATTICE_DISCOVERY_CACHE_MAX_SIZE` (number)\n\t * - `TRACELATTICE_TOOL_INTERLEAVE_TTL_MS`, `TRACELATTICE_TOOL_INTERLEAVE_SWEEP_MS` (milliseconds)\n\t * - `TRACELATTICE_SESSION_MAX_PER_OWNER` (number)\n\t * - `TRACELATTICE_FEATURES_*` (booleans true/false/1/0 or sequential/tot strategy)\n\t * Persistence buffer, flush interval, and retry settings have no environment aliases.\n\t *\n\t * @param config - The configuration to apply overrides to\n\t * @returns A new configuration object with environment overrides applied\n\t */\n\tpublic applyEnvironmentOverrides(config: ConfigFileOptions): ConfigFileOptions {\n\t\tconst result = this.cloneConfig(config);\n\n\t\tif (process.env.TRACELATTICE_MAX_HISTORY_SIZE !== undefined) {\n\t\t\tresult.maxHistorySize = this.parseEnvironmentInteger(\n\t\t\t\t'TRACELATTICE_MAX_HISTORY_SIZE',\n\t\t\t\tprocess.env.TRACELATTICE_MAX_HISTORY_SIZE\n\t\t\t);\n\t\t}\n\t\tif (process.env.TRACELATTICE_MAX_BRANCHES !== undefined) {\n\t\t\tresult.maxBranches = this.parseEnvironmentInteger(\n\t\t\t\t'TRACELATTICE_MAX_BRANCHES',\n\t\t\t\tprocess.env.TRACELATTICE_MAX_BRANCHES\n\t\t\t);\n\t\t}\n\t\tif (process.env.TRACELATTICE_MAX_BRANCH_SIZE !== undefined) {\n\t\t\tresult.maxBranchSize = this.parseEnvironmentInteger(\n\t\t\t\t'TRACELATTICE_MAX_BRANCH_SIZE',\n\t\t\t\tprocess.env.TRACELATTICE_MAX_BRANCH_SIZE\n\t\t\t);\n\t\t}\n\t\tif (\n\t\t\tprocess.env.TRACELATTICE_LOG_LEVEL &&\n\t\t\t['debug', 'info', 'warn', 'error'].includes(process.env.TRACELATTICE_LOG_LEVEL)\n\t\t) {\n\t\t\tresult.logLevel = process.env.TRACELATTICE_LOG_LEVEL as 'debug' | 'info' | 'warn' | 'error';\n\t\t}\n\t\tif (process.env.TRACELATTICE_PRETTY_LOG === 'false') {\n\t\t\tresult.prettyLog = false;\n\t\t}\n\t\tif (process.env.TRACELATTICE_SKILL_DIRS !== undefined) {\n\t\t\tresult.skillDirs =\n\t\t\t\tprocess.env.TRACELATTICE_SKILL_DIRS === ''\n\t\t\t\t\t? []\n\t\t\t\t\t: process.env.TRACELATTICE_SKILL_DIRS.split(':');\n\t\t}\n\t\tif (process.env.TRACELATTICE_TOOL_DIRS !== undefined) {\n\t\t\tresult.toolDirs =\n\t\t\t\tprocess.env.TRACELATTICE_TOOL_DIRS === ''\n\t\t\t\t\t? []\n\t\t\t\t\t: process.env.TRACELATTICE_TOOL_DIRS.split(':');\n\t\t}\n\t\tif (process.env.TRACELATTICE_DISCOVERY_CACHE_TTL !== undefined) {\n\t\t\tconst seconds = this.parseEnvironmentInteger(\n\t\t\t\t'TRACELATTICE_DISCOVERY_CACHE_TTL',\n\t\t\t\tprocess.env.TRACELATTICE_DISCOVERY_CACHE_TTL\n\t\t\t);\n\t\t\tconst ttl = seconds * 1000;\n\t\t\tif (!Number.isSafeInteger(ttl)) {\n\t\t\t\tthrow new ConfigurationError(\n\t\t\t\t\t'TRACELATTICE_DISCOVERY_CACHE_TTL exceeds the safe integer range'\n\t\t\t\t);\n\t\t\t}\n\t\t\tresult.discoveryCache = { ...result.discoveryCache, ttl };\n\t\t}\n\t\tif (process.env.TRACELATTICE_DISCOVERY_CACHE_MAX_SIZE !== undefined) {\n\t\t\tconst maxSize = this.parseEnvironmentInteger(\n\t\t\t\t'TRACELATTICE_DISCOVERY_CACHE_MAX_SIZE',\n\t\t\t\tprocess.env.TRACELATTICE_DISCOVERY_CACHE_MAX_SIZE\n\t\t\t);\n\t\t\tresult.discoveryCache = { ...result.discoveryCache, maxSize };\n\t\t}\n\t\tif (process.env.TRACELATTICE_TOOL_INTERLEAVE_TTL_MS !== undefined) {\n\t\t\tresult.toolInterleaveTtlMs = this.parseEnvironmentInteger(\n\t\t\t\t'TRACELATTICE_TOOL_INTERLEAVE_TTL_MS',\n\t\t\t\tprocess.env.TRACELATTICE_TOOL_INTERLEAVE_TTL_MS\n\t\t\t);\n\t\t}\n\t\tif (process.env.TRACELATTICE_TOOL_INTERLEAVE_SWEEP_MS !== undefined) {\n\t\t\tresult.toolInterleaveSweepMs = this.parseEnvironmentInteger(\n\t\t\t\t'TRACELATTICE_TOOL_INTERLEAVE_SWEEP_MS',\n\t\t\t\tprocess.env.TRACELATTICE_TOOL_INTERLEAVE_SWEEP_MS\n\t\t\t);\n\t\t}\n\t\tif (process.env.TRACELATTICE_SESSION_MAX_PER_OWNER !== undefined) {\n\t\t\tresult.maxSessionsPerOwner = this.parseEnvironmentInteger(\n\t\t\t\t'TRACELATTICE_SESSION_MAX_PER_OWNER',\n\t\t\t\tprocess.env.TRACELATTICE_SESSION_MAX_PER_OWNER\n\t\t\t);\n\t\t}\n\n\t\tthis.applyFeatureFlagOverrides(result);\n\n\t\treturn result;\n\t}\n\n\tprivate cloneConfig(config: ConfigFileOptions): Mutable<ConfigFileOptions> {\n\t\treturn {\n\t\t\t...config,\n\t\t\t...(config.skillDirs === undefined ? {} : { skillDirs: [...config.skillDirs] }),\n\t\t\t...(config.toolDirs === undefined ? {} : { toolDirs: [...config.toolDirs] }),\n\t\t\t...(config.discoveryCache === undefined\n\t\t\t\t? {}\n\t\t\t\t: { discoveryCache: { ...config.discoveryCache } }),\n\t\t\t...(config.persistence === undefined\n\t\t\t\t? {}\n\t\t\t\t: {\n\t\t\t\t\t\tpersistence: {\n\t\t\t\t\t\t\t...config.persistence,\n\t\t\t\t\t\t\t...(config.persistence.options === undefined\n\t\t\t\t\t\t\t\t? {}\n\t\t\t\t\t\t\t\t: { options: { ...config.persistence.options } }),\n\t\t\t\t\t\t},\n\t\t\t\t\t}),\n\t\t\t...(config.features === undefined ? {} : { features: { ...config.features } }),\n\t\t};\n\t}\n\n\t/**\n\t * Applies TRACELATTICE_FEATURES_* environment variable overrides for feature flags.\n\t * Booleans accept 'true'/'false'/'1'/'0' (case-insensitive).\n\t * Invalid reasoningStrategy values are rejected.\n\t *\n\t * @param result - Configuration object to mutate with feature flag overrides\n\t * @private\n\t */\n\tprivate applyFeatureFlagOverrides(result: Mutable<ConfigFileOptions>): void {\n\t\tconst boolMap: Record<string, Exclude<keyof FeatureFlags, 'reasoningStrategy'>> = {\n\t\t\tTRACELATTICE_FEATURES_DAG_EDGES: 'dagEdges',\n\t\t\tTRACELATTICE_FEATURES_CALIBRATION: 'calibration',\n\t\t\tTRACELATTICE_FEATURES_COMPRESSION: 'compression',\n\t\t\tTRACELATTICE_FEATURES_TOOL_INTERLEAVE: 'toolInterleave',\n\t\t\tTRACELATTICE_FEATURES_NEW_THOUGHT_TYPES: 'newThoughtTypes',\n\t\t\tTRACELATTICE_FEATURES_OUTCOME_RECORDING: 'outcomeRecording',\n\t\t};\n\t\tfor (const [envVar, key] of Object.entries(boolMap)) {\n\t\t\tconst raw = process.env[envVar];\n\t\t\tif (raw === undefined) continue;\n\t\t\tconst parsed = this.parseBoolean(raw);\n\t\t\tif (parsed === undefined) {\n\t\t\t\tconsole.warn(\n\t\t\t\t\t`Invalid boolean value for ${envVar}: \"${raw}\" (expected true/false/1/0). Ignoring.`\n\t\t\t\t);\n\t\t\t\tcontinue;\n\t\t\t}\n\t\t\tconst features: { -readonly [K in keyof FeatureFlags]?: FeatureFlags[K] } =\n\t\t\t\tresult.features ?? {};\n\t\t\tfeatures[key] = parsed;\n\t\t\tresult.features = features;\n\t\t}\n\n\t\tconst strategyRaw = process.env.TRACELATTICE_FEATURES_REASONING_STRATEGY;\n\t\tif (strategyRaw !== undefined) {\n\t\t\tif (strategyRaw !== 'sequential' && strategyRaw !== 'tot') {\n\t\t\t\tthrow new ConfigurationError(\n\t\t\t\t\t`TRACELATTICE_FEATURES_REASONING_STRATEGY must be one of sequential, tot, got ${strategyRaw}`\n\t\t\t\t);\n\t\t\t}\n\t\t\tconst features: { -readonly [K in keyof FeatureFlags]?: FeatureFlags[K] } =\n\t\t\t\tresult.features ?? {};\n\t\t\tfeatures.reasoningStrategy = strategyRaw;\n\t\t\tresult.features = features;\n\t\t}\n\t}\n\n\tprivate parseEnvironmentInteger(environmentName: string, raw: string): number {\n\t\tif (!/^(0|[1-9]\\d*)$/.test(raw)) {\n\t\t\tthrow new ConfigurationError(`${environmentName} must be an integer, got ${raw}`);\n\t\t}\n\t\tconst parsed = Number(raw);\n\t\tif (!Number.isSafeInteger(parsed)) {\n\t\t\tthrow new ConfigurationError(`${environmentName} must be a safe integer, got ${raw}`);\n\t\t}\n\t\treturn parsed;\n\t}\n\n\t/**\n\t * Parses a boolean from an environment variable string.\n\t * Accepts 'true'/'false'/'1'/'0' case-insensitively.\n\t *\n\t * @param raw - Raw environment variable string\n\t * @returns Parsed boolean, or undefined if the value is invalid\n\t * @private\n\t */\n\tprivate parseBoolean(raw: string): boolean | undefined {\n\t\tconst v = raw.trim().toLowerCase();\n\t\tif (v === 'true' || v === '1') return true;\n\t\tif (v === 'false' || v === '0') return false;\n\t\treturn undefined;\n\t}\n\n\t/**\n\t * Parses a configuration file (JSON or YAML).\n\t *\n\t * Detects the file type by extension and uses the appropriate parser.\n\t * Supports `.json`, `.yaml`, and `.yml` file extensions.\n\t *\n\t * @param filePath - Path to the configuration file to parse\n\t * @returns The parsed configuration object\n\t * @throws {Error} If the file cannot be parsed\n\t * @private\n\t */\n\tprivate parseConfig(filePath: string): ConfigFileOptions {\n\t\tconst content = readFileSync(filePath, 'utf-8');\n\t\tconst ext = filePath.split('.').pop()?.toLowerCase();\n\n\t\tconst raw: unknown = ext === 'yaml' || ext === 'yml' ? parseYaml(content) : JSON.parse(content);\n\n\t\treturn v.parse(ConfigFileOptionsSchema, raw) as ConfigFileOptions;\n\t}\n\n\t/**\n\t * Converts file-based configuration to ServerConfig options.\n\t *\n\t * This is a convenience method for extracting the ServerConfig-relevant\n\t * options from a file-based configuration.\n\t *\n\t * @param config - The configuration to convert\n\t * @returns An object with ServerConfig-compatible options\n\t *\n\t * @example\n\t * ```typescript\n\t * const loader = new ConfigLoader();\n\t * const config = loader.load();\n\t * if (config) {\n\t * const serverOpts = loader.toServerConfigOptions(config);\n\t * const serverConfig = new ServerConfig(serverOpts);\n\t * }\n\t * ```\n\t */\n\ttoServerConfigOptions(config: ConfigFileOptions): ServerConfigOptions {\n\t\treturn {\n\t\t\tmaxHistorySize: config.maxHistorySize,\n\t\t\tmaxBranches: config.maxBranches,\n\t\t\tmaxBranchSize: config.maxBranchSize,\n\t\t\tskillDirs: config.skillDirs,\n\t\t\ttoolDirs: config.toolDirs,\n\t\t\tdiscoveryCache: config.discoveryCache,\n\t\t\tpersistence: config.persistence,\n\t\t\tpersistenceBufferSize: config.persistenceBufferSize,\n\t\t\tpersistenceFlushInterval: config.persistenceFlushInterval,\n\t\t\tpersistenceMaxRetries: config.persistenceMaxRetries,\n\t\t\tfeatures: config.features,\n\t\t\ttoolInterleaveTtlMs: config.toolInterleaveTtlMs,\n\t\t\ttoolInterleaveSweepMs: config.toolInterleaveSweepMs,\n\t\t\tmaxSessionsPerOwner: config.maxSessionsPerOwner,\n\t\t};\n\t}\n}\n"],"names":["ConfigFileOptionsSchema","v","ConfigLoader","customPath","configuredPath","process","join","homedir","config","configPath","existsSync","error","console","getErrorMessage","result","undefined","seconds","ttl","Number","ConfigurationError","maxSize","boolMap","envVar","key","Object","raw","parsed","features","strategyRaw","environmentName","filePath","content","readFileSync","ext","parseYaml","JSON"],"mappings":"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"}
|
|
@@ -1,9 +1,18 @@
|
|
|
1
1
|
import type { ThoughtData } from '../core/thought.js';
|
|
2
2
|
import type { Edge } from '../core/graph/Edge.js';
|
|
3
3
|
import type { Summary } from '../core/compression/Summary.js';
|
|
4
|
-
import type { BranchId, SessionId } from './ids.js';
|
|
4
|
+
import type { BranchId, SessionId, ThoughtId } from './ids.js';
|
|
5
5
|
export interface PersistenceBackend {
|
|
6
6
|
saveThoughtForSession(sessionId: SessionId, thought: ThoughtData): Promise<void>;
|
|
7
|
+
/**
|
|
8
|
+
* Atomically persist a backtrack correction for one session.
|
|
9
|
+
*
|
|
10
|
+
* Implementations must retract every retained stable-ID copy of `targetThoughtId`, append
|
|
11
|
+
* `thought`, and apply retention as one all-or-none operation. This is a required contract,
|
|
12
|
+
* including for custom backends: callers do not probe for it or fall back to ordinary writes.
|
|
13
|
+
* The ordinary persistence methods keep their existing contracts.
|
|
14
|
+
*/
|
|
15
|
+
saveBacktrackForSession(sessionId: SessionId, thought: ThoughtData, targetThoughtId: ThoughtId): Promise<void>;
|
|
7
16
|
loadHistoryForSession(sessionId: SessionId): Promise<ThoughtData[]>;
|
|
8
17
|
saveBranchForSession(sessionId: SessionId, branchId: BranchId, thoughts: readonly ThoughtData[]): Promise<void>;
|
|
9
18
|
deleteBranchForSession(sessionId: SessionId, branchId: BranchId): Promise<void>;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"PersistenceBackend.d.ts","sourceRoot":"","sources":["../../src/contracts/PersistenceBackend.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,oBAAoB,CAAC;AACtD,OAAO,KAAK,EAAE,IAAI,EAAE,MAAM,uBAAuB,CAAC;AAClD,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,gCAAgC,CAAC;AAC9D,OAAO,KAAK,EAAE,QAAQ,EAAE,SAAS,EAAE,MAAM,UAAU,CAAC;
|
|
1
|
+
{"version":3,"file":"PersistenceBackend.d.ts","sourceRoot":"","sources":["../../src/contracts/PersistenceBackend.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,oBAAoB,CAAC;AACtD,OAAO,KAAK,EAAE,IAAI,EAAE,MAAM,uBAAuB,CAAC;AAClD,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,gCAAgC,CAAC;AAC9D,OAAO,KAAK,EAAE,QAAQ,EAAE,SAAS,EAAE,SAAS,EAAE,MAAM,UAAU,CAAC;AAE/D,MAAM,WAAW,kBAAkB;IAClC,qBAAqB,CAAC,SAAS,EAAE,SAAS,EAAE,OAAO,EAAE,WAAW,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC;IACjF;;;;;;;OAOG;IACH,uBAAuB,CACtB,SAAS,EAAE,SAAS,EACpB,OAAO,EAAE,WAAW,EACpB,eAAe,EAAE,SAAS,GACxB,OAAO,CAAC,IAAI,CAAC,CAAC;IACjB,qBAAqB,CAAC,SAAS,EAAE,SAAS,GAAG,OAAO,CAAC,WAAW,EAAE,CAAC,CAAC;IACpE,oBAAoB,CACnB,SAAS,EAAE,SAAS,EACpB,QAAQ,EAAE,QAAQ,EAClB,QAAQ,EAAE,SAAS,WAAW,EAAE,GAC9B,OAAO,CAAC,IAAI,CAAC,CAAC;IACjB,sBAAsB,CAAC,SAAS,EAAE,SAAS,EAAE,QAAQ,EAAE,QAAQ,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC;IAChF,oBAAoB,CACnB,SAAS,EAAE,SAAS,EACpB,QAAQ,EAAE,QAAQ,GAChB,OAAO,CAAC,WAAW,EAAE,GAAG,SAAS,CAAC,CAAC;IACtC,sBAAsB,CAAC,SAAS,EAAE,SAAS,GAAG,OAAO,CAAC,QAAQ,EAAE,CAAC,CAAC;IAClE,YAAY,IAAI,OAAO,CAAC,SAAS,EAAE,CAAC,CAAC;IACrC,OAAO,IAAI,OAAO,CAAC,OAAO,CAAC,CAAC;IAC5B,YAAY,CAAC,SAAS,EAAE,SAAS,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC;IAClD,QAAQ,IAAI,OAAO,CAAC,IAAI,CAAC,CAAC;IAC1B,SAAS,CAAC,SAAS,EAAE,SAAS,EAAE,KAAK,EAAE,SAAS,IAAI,EAAE,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC;IACvE,SAAS,CAAC,SAAS,EAAE,SAAS,GAAG,OAAO,CAAC,IAAI,EAAE,CAAC,CAAC;IACjD,aAAa,CAAC,SAAS,EAAE,SAAS,EAAE,SAAS,EAAE,SAAS,OAAO,EAAE,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC;IAClF,aAAa,CAAC,SAAS,EAAE,SAAS,GAAG,OAAO,CAAC,OAAO,EAAE,CAAC,CAAC;IACxD,KAAK,IAAI,OAAO,CAAC,IAAI,CAAC,CAAC;CACvB;AAED,MAAM,WAAW,iBAAiB;IACjC,OAAO,CAAC,EAAE,OAAO,CAAC;IAClB,OAAO,CAAC,EAAE,MAAM,GAAG,QAAQ,GAAG,QAAQ,CAAC;IACvC,OAAO,CAAC,EAAE;QACT,OAAO,CAAC,EAAE,MAAM,CAAC;QACjB,MAAM,CAAC,EAAE,MAAM,CAAC;QAChB,SAAS,CAAC,EAAE,OAAO,CAAC;QACpB,cAAc,CAAC,EAAE,MAAM,CAAC;QACxB,eAAe,CAAC,EAAE,OAAO,CAAC;KAC1B,CAAC;CACF"}
|