@iworkforces/tracelattice 2.0.8 → 2.1.2

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.
Files changed (178) hide show
  1. package/README.md +89 -64
  2. package/dist/ServerConfig.d.ts +1 -1
  3. package/dist/ServerConfig.js.map +1 -1
  4. package/dist/cli.js +18 -73
  5. package/dist/cli.js.map +1 -1
  6. package/dist/config/ConfigLoader.d.ts +29 -26
  7. package/dist/config/ConfigLoader.d.ts.map +1 -1
  8. package/dist/config/ConfigLoader.js +40 -36
  9. package/dist/config/ConfigLoader.js.map +1 -1
  10. package/dist/contracts/PersistenceBackend.d.ts +7 -108
  11. package/dist/contracts/PersistenceBackend.d.ts.map +1 -1
  12. package/dist/contracts/PersistenceBackend.js +1 -6
  13. package/dist/contracts/calibrator.d.ts +6 -6
  14. package/dist/contracts/calibrator.d.ts.map +1 -1
  15. package/dist/contracts/ids.d.ts +1 -8
  16. package/dist/contracts/ids.d.ts.map +1 -1
  17. package/dist/contracts/ids.js +2 -3
  18. package/dist/contracts/ids.js.map +1 -1
  19. package/dist/contracts/interfaces.d.ts +4 -6
  20. package/dist/contracts/interfaces.d.ts.map +1 -1
  21. package/dist/contracts/persistence-work.d.ts +2 -3
  22. package/dist/contracts/persistence-work.d.ts.map +1 -1
  23. package/dist/core/HistoryManager.d.ts +12 -16
  24. package/dist/core/HistoryManager.d.ts.map +1 -1
  25. package/dist/core/HistoryManager.js +19 -40
  26. package/dist/core/HistoryManager.js.map +1 -1
  27. package/dist/core/IHistoryManager.d.ts +22 -30
  28. package/dist/core/IHistoryManager.d.ts.map +1 -1
  29. package/dist/core/InputNormalizer.d.ts +7 -24
  30. package/dist/core/InputNormalizer.d.ts.map +1 -1
  31. package/dist/core/InputNormalizer.js +3 -9
  32. package/dist/core/InputNormalizer.js.map +1 -1
  33. package/dist/core/PersistenceBuffer.d.ts +3 -20
  34. package/dist/core/PersistenceBuffer.d.ts.map +1 -1
  35. package/dist/core/PersistenceBuffer.js +1 -4
  36. package/dist/core/PersistenceBuffer.js.map +1 -1
  37. package/dist/core/PersistenceRestore.d.ts.map +1 -1
  38. package/dist/core/PersistenceRestore.js +4 -10
  39. package/dist/core/PersistenceRestore.js.map +1 -1
  40. package/dist/core/PersistenceWriter.d.ts.map +1 -1
  41. package/dist/core/PersistenceWriter.js +3 -12
  42. package/dist/core/PersistenceWriter.js.map +1 -1
  43. package/dist/core/SessionErrors.d.ts +0 -11
  44. package/dist/core/SessionErrors.d.ts.map +1 -1
  45. package/dist/core/SessionErrors.js +1 -14
  46. package/dist/core/SessionErrors.js.map +1 -1
  47. package/dist/core/SessionLock.d.ts +4 -5
  48. package/dist/core/SessionLock.d.ts.map +1 -1
  49. package/dist/core/SessionLock.js +5 -10
  50. package/dist/core/SessionLock.js.map +1 -1
  51. package/dist/core/SessionManager.d.ts +0 -2
  52. package/dist/core/SessionManager.d.ts.map +1 -1
  53. package/dist/core/SessionManager.js +3 -5
  54. package/dist/core/SessionManager.js.map +1 -1
  55. package/dist/core/SessionResetCoordinator.d.ts +10 -7
  56. package/dist/core/SessionResetCoordinator.d.ts.map +1 -1
  57. package/dist/core/SessionResetCoordinator.js +10 -28
  58. package/dist/core/SessionResetCoordinator.js.map +1 -1
  59. package/dist/core/ThoughtEvaluator.d.ts +5 -5
  60. package/dist/core/ThoughtEvaluator.d.ts.map +1 -1
  61. package/dist/core/ThoughtEvaluator.js +4 -40
  62. package/dist/core/ThoughtEvaluator.js.map +1 -1
  63. package/dist/core/ThoughtProcessor.d.ts +10 -3
  64. package/dist/core/ThoughtProcessor.d.ts.map +1 -1
  65. package/dist/core/ThoughtProcessor.js +34 -38
  66. package/dist/core/ThoughtProcessor.js.map +1 -1
  67. package/dist/core/VerificationOutcomeAdmission.d.ts.map +1 -1
  68. package/dist/core/VerificationOutcomeAdmission.js +5 -7
  69. package/dist/core/VerificationOutcomeAdmission.js.map +1 -1
  70. package/dist/core/evaluator/Calibrator.d.ts +1 -1
  71. package/dist/core/evaluator/Calibrator.d.ts.map +1 -1
  72. package/dist/core/evaluator/Calibrator.js +2 -5
  73. package/dist/core/evaluator/Calibrator.js.map +1 -1
  74. package/dist/core/evaluator/internals.d.ts +0 -4
  75. package/dist/core/evaluator/internals.d.ts.map +1 -1
  76. package/dist/core/evaluator/internals.js +1 -3
  77. package/dist/core/evaluator/internals.js.map +1 -1
  78. package/dist/core/graph/Edge.d.ts +1 -1
  79. package/dist/core/graph/EdgeEmitter.d.ts +2 -4
  80. package/dist/core/graph/EdgeEmitter.d.ts.map +1 -1
  81. package/dist/core/graph/EdgeEmitter.js +2 -4
  82. package/dist/core/graph/EdgeEmitter.js.map +1 -1
  83. package/dist/core/reasoning/OutcomeRecorder.d.ts +0 -1
  84. package/dist/core/reasoning/OutcomeRecorder.d.ts.map +1 -1
  85. package/dist/core/reasoning/OutcomeRecorder.js.map +1 -1
  86. package/dist/core/reasoning/strategies/SequentialStrategy.d.ts +3 -3
  87. package/dist/core/reasoning/strategies/SequentialStrategy.js.map +1 -1
  88. package/dist/core/thought.d.ts +2 -1
  89. package/dist/core/thought.d.ts.map +1 -1
  90. package/dist/errors.d.ts +4 -20
  91. package/dist/errors.d.ts.map +1 -1
  92. package/dist/errors.js +2 -28
  93. package/dist/errors.js.map +1 -1
  94. package/dist/lib.d.ts +13 -20
  95. package/dist/lib.d.ts.map +1 -1
  96. package/dist/lib.js +4 -7
  97. package/dist/lib.js.map +1 -1
  98. package/dist/logger/NullLogger.d.ts +9 -11
  99. package/dist/logger/NullLogger.d.ts.map +1 -1
  100. package/dist/logger/NullLogger.js.map +1 -1
  101. package/dist/persistence/FilePersistence.d.ts +3 -12
  102. package/dist/persistence/FilePersistence.d.ts.map +1 -1
  103. package/dist/persistence/FilePersistence.js +9 -61
  104. package/dist/persistence/FilePersistence.js.map +1 -1
  105. package/dist/persistence/FileSnapshotV2.d.ts +2 -2
  106. package/dist/persistence/FileSnapshotV2.js +2 -2
  107. package/dist/persistence/FileSnapshotV2.js.map +1 -1
  108. package/dist/persistence/FileWriter.d.ts +1 -0
  109. package/dist/persistence/FileWriter.d.ts.map +1 -1
  110. package/dist/persistence/FileWriter.js +3 -3
  111. package/dist/persistence/FileWriter.js.map +1 -1
  112. package/dist/persistence/MemoryPersistence.d.ts +5 -15
  113. package/dist/persistence/MemoryPersistence.d.ts.map +1 -1
  114. package/dist/persistence/MemoryPersistence.js +6 -40
  115. package/dist/persistence/MemoryPersistence.js.map +1 -1
  116. package/dist/persistence/PersistenceCodec.js +1 -3
  117. package/dist/persistence/PersistenceCodec.js.map +1 -1
  118. package/dist/persistence/PersistenceErrors.d.ts +0 -6
  119. package/dist/persistence/PersistenceErrors.d.ts.map +1 -1
  120. package/dist/persistence/PersistenceErrors.js +1 -9
  121. package/dist/persistence/PersistenceErrors.js.map +1 -1
  122. package/dist/persistence/PersistenceScope.d.ts.map +1 -1
  123. package/dist/persistence/PersistenceScope.js +2 -2
  124. package/dist/persistence/PersistenceScope.js.map +1 -1
  125. package/dist/persistence/SqlitePersistence.d.ts +3 -10
  126. package/dist/persistence/SqlitePersistence.d.ts.map +1 -1
  127. package/dist/persistence/SqlitePersistence.js +2 -26
  128. package/dist/persistence/SqlitePersistence.js.map +1 -1
  129. package/dist/persistence/SqliteSchemaV2.d.ts.map +1 -1
  130. package/dist/persistence/SqliteSchemaV2.js +3 -12
  131. package/dist/persistence/SqliteSchemaV2.js.map +1 -1
  132. package/dist/pool/ConnectionPool.d.ts +3 -12
  133. package/dist/pool/ConnectionPool.d.ts.map +1 -1
  134. package/dist/pool/ConnectionPool.js +5 -8
  135. package/dist/pool/ConnectionPool.js.map +1 -1
  136. package/dist/pool/IConnectionPool.d.ts +3 -9
  137. package/dist/pool/IConnectionPool.d.ts.map +1 -1
  138. package/dist/registry/BaseRegistry.d.ts +10 -2
  139. package/dist/registry/BaseRegistry.d.ts.map +1 -1
  140. package/dist/registry/BaseRegistry.js +128 -81
  141. package/dist/registry/BaseRegistry.js.map +1 -1
  142. package/dist/registry/SkillRegistry.d.ts +1 -7
  143. package/dist/registry/SkillRegistry.d.ts.map +1 -1
  144. package/dist/registry/SkillRegistry.js +0 -15
  145. package/dist/registry/SkillRegistry.js.map +1 -1
  146. package/dist/registry/ToolRegistry.d.ts +1 -9
  147. package/dist/registry/ToolRegistry.d.ts.map +1 -1
  148. package/dist/registry/ToolRegistry.js +0 -21
  149. package/dist/registry/ToolRegistry.js.map +1 -1
  150. package/dist/schema.d.ts +2 -1
  151. package/dist/schema.d.ts.map +1 -1
  152. package/dist/schema.js +3 -3
  153. package/dist/schema.js.map +1 -1
  154. package/dist/transport/BaseTransport.d.ts +0 -9
  155. package/dist/transport/BaseTransport.d.ts.map +1 -1
  156. package/dist/transport/BaseTransport.js +0 -11
  157. package/dist/transport/BaseTransport.js.map +1 -1
  158. package/dist/watchers/SkillWatcher.d.ts.map +1 -1
  159. package/dist/watchers/SkillWatcher.js +1 -1
  160. package/dist/watchers/SkillWatcher.js.map +1 -1
  161. package/package.json +1 -1
  162. package/dist/contracts/PersistenceBackend.js.map +0 -1
  163. package/dist/persistence/FileLegacyImport.d.ts +0 -2
  164. package/dist/persistence/FileLegacyImport.d.ts.map +0 -1
  165. package/dist/persistence/FileLegacyImport.js +0 -183
  166. package/dist/persistence/FileLegacyImport.js.map +0 -1
  167. package/dist/persistence/SessionScopedPersistence.d.ts +0 -4
  168. package/dist/persistence/SessionScopedPersistence.d.ts.map +0 -1
  169. package/dist/persistence/SessionScopedPersistence.js +0 -9
  170. package/dist/persistence/SessionScopedPersistence.js.map +0 -1
  171. package/dist/persistence/SqliteLegacyImport.d.ts +0 -14
  172. package/dist/persistence/SqliteLegacyImport.d.ts.map +0 -1
  173. package/dist/persistence/SqliteLegacyImport.js +0 -136
  174. package/dist/persistence/SqliteLegacyImport.js.map +0 -1
  175. package/dist/persistence/SqliteLegacySchema.d.ts +0 -15
  176. package/dist/persistence/SqliteLegacySchema.d.ts.map +0 -1
  177. package/dist/persistence/SqliteLegacySchema.js +0 -72
  178. package/dist/persistence/SqliteLegacySchema.js.map +0 -1
@@ -1 +1 @@
1
- {"version":3,"file":"BaseRegistry.d.ts","sourceRoot":"","sources":["../../src/registry/BaseRegistry.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"BaseRegistry.d.ts","sourceRoot":"","sources":["../../src/registry/BaseRegistry.ts"],"names":[],"mappings":"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"}
@@ -14,7 +14,10 @@ class BaseRegistry {
14
14
  _searchDirs;
15
15
  _discovered = false;
16
16
  _discoveryPromise = null;
17
- _refreshRequested = false;
17
+ _activeDiscoveryEpoch = null;
18
+ _queuedRefreshEpoch = null;
19
+ _replacementEpoch = 0;
20
+ _discoveredCount = 0;
18
21
  constructor(options){
19
22
  this._items = new Map();
20
23
  this._manualItems = new Map();
@@ -41,9 +44,11 @@ class BaseRegistry {
41
44
  }
42
45
  remove(name) {
43
46
  if (!this._items.has(name)) throw this._createNotFoundError(name, 'remove');
44
- this._items.delete(name);
45
- this._manualItems.delete(name);
46
- for (const [filePath, item] of this._discoveredItemsByPath)if (item.name === name) this._discoveredItemsByPath.delete(filePath);
47
+ const removedManualItem = this._manualItems.delete(name);
48
+ if (!removedManualItem) {
49
+ for (const [filePath, item] of this._discoveredItemsByPath)if (item.name === name) this._discoveredItemsByPath.delete(filePath);
50
+ }
51
+ this._rebuildVisibleItems();
47
52
  this.log(`Removed ${this._entityName}: ${name}`, {
48
53
  [`${this._entityName}Name`]: name
49
54
  });
@@ -52,14 +57,16 @@ class BaseRegistry {
52
57
  }
53
58
  update(name, updates) {
54
59
  if (!this._items.has(name)) throw this._createNotFoundError(name, 'update');
60
+ const isManualItem = this._manualItems.has(name);
55
61
  const existing = this._items.get(name);
56
62
  const updated = {
57
63
  ...existing,
58
- ...updates
64
+ ...updates,
65
+ name
59
66
  };
60
67
  this._items.set(name, updated);
61
- if (this._manualItems.has(name)) this._manualItems.set(name, updated);
62
- for (const [filePath, item] of this._discoveredItemsByPath)if (item.name === name) this._discoveredItemsByPath.set(filePath, updated);
68
+ if (isManualItem) this._manualItems.set(name, updated);
69
+ else for (const [filePath, item] of this._discoveredItemsByPath)if (item.name === name) this._discoveredItemsByPath.set(filePath, updated);
63
70
  this.log(`Updated ${this._entityName}: ${name}`, {
64
71
  [`${this._entityName}Name`]: name
65
72
  });
@@ -85,110 +92,150 @@ class BaseRegistry {
85
92
  return Array.from(this._items.keys());
86
93
  }
87
94
  clear() {
88
- this._items.clear();
89
- this._manualItems.clear();
90
- this._discoveredItemsByPath.clear();
95
+ this._beginReplacement();
91
96
  this.log(`Cleared all ${this._entityName}s`);
92
- this._cache?.clear();
93
97
  }
94
98
  size() {
95
99
  return this._items.size;
96
100
  }
97
101
  async discoverAsync() {
98
- if (this._discoveryPromise) return this._discoveryPromise;
99
- if (this._discovered) {
100
- const cached = this._cache.get('all');
101
- return cached?.length ?? 0;
102
+ if (this._discoveryPromise) {
103
+ if (!this._discovered && this._activeDiscoveryEpoch !== this._replacementEpoch) this._queuedRefreshEpoch = this._replacementEpoch;
104
+ return this._discoveryPromise;
102
105
  }
106
+ if (this._discovered) return this._discoveredCount;
103
107
  return this._beginDiscovery();
104
108
  }
105
109
  async refreshAsync() {
106
- this._refreshRequested = true;
107
- return this._discoveryPromise ?? this._beginDiscovery();
110
+ if (this._discoveryPromise) {
111
+ this._queuedRefreshEpoch = this._replacementEpoch;
112
+ return this._discoveryPromise;
113
+ }
114
+ return this._beginDiscovery();
108
115
  }
109
116
  _beginDiscovery() {
110
117
  const operation = this._runDiscoveryLoop();
111
118
  this._discoveryPromise = operation;
112
- const clearOperation = ()=>{
113
- if (this._discoveryPromise === operation) this._discoveryPromise = null;
114
- };
115
- operation.then(clearOperation, clearOperation);
116
119
  return operation;
117
120
  }
118
121
  async _runDiscoveryLoop() {
119
- this._refreshRequested = false;
120
- let count = await this._performDiscovery();
121
- while(this._refreshRequested){
122
- this._refreshRequested = false;
123
- count = await this._performDiscovery();
122
+ let passEpoch = this._replacementEpoch;
123
+ try {
124
+ while(true){
125
+ this._activeDiscoveryEpoch = passEpoch;
126
+ let count;
127
+ try {
128
+ count = await this._performDiscovery(passEpoch);
129
+ } finally{
130
+ this._activeDiscoveryEpoch = null;
131
+ }
132
+ const queuedEpoch = this._queuedRefreshEpoch;
133
+ this._queuedRefreshEpoch = null;
134
+ if (null === queuedEpoch) return count;
135
+ passEpoch = queuedEpoch;
136
+ }
137
+ } finally{
138
+ this._discoveryPromise = null;
124
139
  }
125
- return count;
126
- }
127
- async _performDiscovery() {
128
- const discoveredItems = new Map();
129
- const claimedNames = new Set(this._manualItems.keys());
130
- for (const dir of this._searchDirs)try {
131
- if (!existsSync(dir)) continue;
132
- const entries = await readdir(dir, {
140
+ }
141
+ async _performDiscovery(epoch = this._replacementEpoch) {
142
+ const scan = {
143
+ itemsByPath: new Map(),
144
+ claimedNames: new Set(),
145
+ previousItemsByPath: new Map(this._discoveredItemsByPath),
146
+ warnings: []
147
+ };
148
+ for (const dir of this._searchDirs)await this._scanDirectory(dir, scan);
149
+ return this._publishDiscovery(epoch, scan);
150
+ }
151
+ async _scanDirectory(directory, scan) {
152
+ try {
153
+ if (!existsSync(directory)) return;
154
+ const entries = await readdir(directory, {
133
155
  withFileTypes: true
134
156
  });
135
- for (const entry of entries)if (!this._shouldSkipFile(entry.name)) {
136
- if (entry.isFile() && this._fileExtensions.some((ext)=>entry.name.endsWith(ext))) {
137
- const filePath = join(dir, entry.name);
138
- try {
139
- const content = await readFile(filePath, 'utf-8');
140
- const parsed = this._parseFrontmatter(content);
141
- if (parsed._error) {
142
- this._retainLastKnownGood(filePath, parsed._error, discoveredItems, claimedNames);
143
- continue;
144
- }
145
- if (parsed.name) {
146
- const item = this._buildItem(parsed);
147
- if (item && !claimedNames.has(item.name)) {
148
- discoveredItems.set(filePath, item);
149
- claimedNames.add(item.name);
150
- }
151
- }
152
- } catch (readError) {
153
- this._retainLastKnownGood(filePath, getErrorMessage(readError), discoveredItems, claimedNames);
154
- }
155
- }
157
+ for (const entry of entries)if (!this._shouldSkipFile(entry.name) && entry.isFile()) {
158
+ if (this._fileExtensions.some((extension)=>entry.name.endsWith(extension))) await this._scanFile(join(directory, entry.name), scan);
156
159
  }
157
160
  } catch (error) {
158
- this._logger.warn(`Failed to scan ${this._entityName} directory`, {
159
- directory: dir,
160
- error: getErrorMessage(error)
161
+ scan.warnings.push({
162
+ message: `Failed to scan ${this._entityName} directory`,
163
+ meta: {
164
+ directory,
165
+ error: getErrorMessage(error)
166
+ }
161
167
  });
162
- this._retainDirectory(dir, discoveredItems, claimedNames);
168
+ this._retainDirectory(directory, scan);
163
169
  }
164
- this._discoveredItemsByPath = discoveredItems;
165
- this._items = new Map(this._manualItems);
166
- for (const item of discoveredItems.values())if (!this._items.has(item.name)) this._items.set(item.name, item);
170
+ }
171
+ async _scanFile(filePath, scan) {
172
+ try {
173
+ const content = await readFile(filePath, 'utf-8');
174
+ const parsed = this._parseFrontmatter(content);
175
+ if (parsed._error) return void this._retainLastKnownGood(filePath, parsed._error, scan);
176
+ if (!parsed.name) return;
177
+ const item = this._buildItem(parsed);
178
+ if (item && !scan.claimedNames.has(item.name)) {
179
+ scan.itemsByPath.set(filePath, item);
180
+ scan.claimedNames.add(item.name);
181
+ }
182
+ } catch (error) {
183
+ this._retainLastKnownGood(filePath, getErrorMessage(error), scan);
184
+ }
185
+ }
186
+ _retainLastKnownGood(filePath, reason, scan) {
187
+ const previous = scan.previousItemsByPath.get(filePath);
188
+ if (previous && !scan.claimedNames.has(previous.name)) {
189
+ scan.itemsByPath.set(filePath, previous);
190
+ scan.claimedNames.add(previous.name);
191
+ }
192
+ scan.warnings.push({
193
+ message: `Invalid ${this._entityName} discovery file`,
194
+ meta: {
195
+ filePath,
196
+ reason,
197
+ retainedLastKnownGood: void 0 !== previous
198
+ }
199
+ });
200
+ }
201
+ _retainDirectory(directory, scan) {
202
+ for (const [filePath, item] of scan.previousItemsByPath)if (dirname(filePath) === directory && !scan.claimedNames.has(item.name)) {
203
+ scan.itemsByPath.set(filePath, item);
204
+ scan.claimedNames.add(item.name);
205
+ }
206
+ }
207
+ _publishDiscovery(epoch, scan) {
208
+ if (epoch !== this._replacementEpoch) return this._discoveredCount;
209
+ this._discoveredItemsByPath = scan.itemsByPath;
210
+ this._rebuildVisibleItems();
167
211
  this._discovered = true;
168
212
  this._cache.clear();
169
213
  this._cache.set('all', Array.from(this._items.values()));
170
- this.log(`Discovery complete: found ${discoveredItems.size} ${this._entityName}s`, {
171
- discoveredCount: discoveredItems.size
214
+ for (const warning of scan.warnings)this._logger.warn(warning.message, warning.meta);
215
+ this.log(`Discovery complete: found ${this._discoveredCount} ${this._entityName}s`, {
216
+ discoveredCount: this._discoveredCount
172
217
  });
173
- return discoveredItems.size;
218
+ return this._discoveredCount;
174
219
  }
175
- _retainLastKnownGood(filePath, reason, discoveredItems, claimedNames) {
176
- const previous = this._discoveredItemsByPath.get(filePath);
177
- if (previous && !claimedNames.has(previous.name)) {
178
- discoveredItems.set(filePath, previous);
179
- claimedNames.add(previous.name);
220
+ _rebuildVisibleItems() {
221
+ const visibleItems = new Map(this._manualItems);
222
+ let visibleDiscoveredCount = 0;
223
+ for (const item of this._discoveredItemsByPath.values())if (!visibleItems.has(item.name)) {
224
+ visibleItems.set(item.name, item);
225
+ visibleDiscoveredCount++;
180
226
  }
181
- this._logger.warn(`Invalid ${this._entityName} discovery file`, {
182
- filePath,
183
- reason,
184
- retainedLastKnownGood: void 0 !== previous
185
- });
227
+ this._items = visibleItems;
228
+ this._discoveredCount = visibleDiscoveredCount;
186
229
  }
187
- _retainDirectory(directory, discoveredItems, claimedNames) {
188
- for (const [filePath, item] of this._discoveredItemsByPath)if (dirname(filePath) === directory && !claimedNames.has(item.name)) {
189
- discoveredItems.set(filePath, item);
190
- claimedNames.add(item.name);
191
- }
230
+ _beginReplacement() {
231
+ this._replacementEpoch++;
232
+ this._queuedRefreshEpoch = null;
233
+ this._items.clear();
234
+ this._manualItems.clear();
235
+ this._discoveredItemsByPath.clear();
236
+ this._discovered = false;
237
+ this._discoveredCount = 0;
238
+ this._cache.clear();
192
239
  }
193
240
  _extractFrontmatter(content) {
194
241
  const match = content.match(/^---\n([\s\S]+?)\n---/);
@@ -196,7 +243,7 @@ class BaseRegistry {
196
243
  return parse(match[1]);
197
244
  }
198
245
  setAll(items) {
199
- this.clear();
246
+ this._beginReplacement();
200
247
  for (const item of items)try {
201
248
  this.add(item);
202
249
  } catch (error) {
@@ -1 +1 @@
1
- {"version":3,"file":"registry/BaseRegistry.js","sources":["../../src/registry/BaseRegistry.ts"],"sourcesContent":["/**\n * Base registry providing shared CRUD, caching, and discovery logic.\n *\n * This abstract generic class extracts the common patterns from `ToolRegistry`\n * and `SkillRegistry` into a single reusable base. Subclasses only need to\n * implement item-specific parsing, file filtering, and error construction.\n *\n * @template T - The registry item type (must have a `name` property)\n * @module registry\n */\n\nimport { existsSync } from 'node:fs';\nimport { readdir, readFile } from 'node:fs/promises';\nimport { dirname, join } from 'node:path';\nimport { parse as parseYaml } from 'yaml';\nimport { DiscoveryCache } from '../cache/DiscoveryCache.js';\nimport { NullLogger } from '../logger/NullLogger.js';\nimport type { Logger } from '../logger/StructuredLogger.js';\nimport { getErrorMessage } from '../errors.js';\n\n/**\n * Configuration options for creating a `BaseRegistry` instance.\n */\nexport interface BaseRegistryOptions {\n\t/** Optional logger for diagnostics. */\n\tlogger?: Logger;\n\n\t/** Optional cache for lookups. */\n\tcache?: DiscoveryCache<{ name: string }>;\n\n\t/**\n\t * Directory paths to search for items.\n\t */\n\tsearchDirs?: string[];\n\n\t/**\n\t * Enable lazy discovery (discover on first access instead of startup).\n\t * @default false\n\t */\n\tlazyDiscovery?: boolean;\n}\n\n/**\n * Abstract base registry for managing named items with discovery and caching.\n *\n * Provides shared CRUD operations, filesystem discovery with deduplication,\n * and optional LRU caching. Subclasses implement item-specific parsing logic\n * and error construction.\n *\n * @template T - The registry item type (must have a `name` property)\n */\nexport abstract class BaseRegistry<T extends { name: string }> {\n\t/** Internal storage for items indexed by name. */\n\tprotected _items: Map<string, T>;\n\tprivate _manualItems: Map<string, T>;\n\tprivate _discoveredItemsByPath: Map<string, T>;\n\n\t/** Logger for diagnostics. */\n\tprotected _logger: Logger;\n\n\t/** Optional cache for lookups. */\n\tprotected _cache: DiscoveryCache<T>;\n\n\t/** Directory paths to search for items. */\n\tprotected _searchDirs: string[];\n\n\t/** Whether discovery has been performed. */\n\tprotected _discovered: boolean = false;\n\n\t/** Promise for in-progress discovery (null if not in progress). */\n\tprotected _discoveryPromise: Promise<number> | null = null;\n\tprivate _refreshRequested = false;\n\n\t/** File extensions to match during discovery. */\n\tprotected abstract readonly _fileExtensions: string[];\n\n\t/**\n\t * Creates an error for invalid item data.\n\t * @param reason - The reason for the validation failure\n\t */\n\tprotected abstract _createInvalidError(reason: string): Error;\n\n\t/**\n\t * Creates an error for duplicate items.\n\t * @param name - The name of the duplicate item\n\t */\n\tprotected abstract _createDuplicateError(name: string): Error;\n\n\t/**\n\t * Creates an error for items not found.\n\t * @param name - The name of the missing item\n\t * @param action - The action that was attempted\n\t */\n\tprotected abstract _createNotFoundError(name: string, action: string): Error;\n\n\t/**\n\t * Parses frontmatter content into a partial item.\n\t * @param content - The file content to parse\n\t * @returns A partial item, with an `_error` property if parsing failed\n\t */\n\tprotected abstract _parseFrontmatter(content: string): Partial<T> & { _error?: string };\n\n\t/**\n\t * Determines whether a file should be skipped during discovery.\n\t * @param fileName - The name of the file to check\n\t * @returns true if the file should be skipped\n\t */\n\tprotected abstract _shouldSkipFile(fileName: string): boolean;\n\n\t/**\n\t * Constructs a complete item from parsed frontmatter data.\n\t * Returns null if the parsed data is insufficient.\n\t * @param parsed - The parsed frontmatter data\n\t * @returns A complete item, or null if data is insufficient\n\t */\n\tprotected abstract _buildItem(parsed: Partial<T>): T | null;\n\n\t/**\n\t * The entity name used in log messages (e.g., 'tool', 'skill').\n\t */\n\tprotected abstract readonly _entityName: string;\n\n\tconstructor(options: BaseRegistryOptions) {\n\t\tthis._items = new Map();\n\t\tthis._manualItems = new Map();\n\t\tthis._discoveredItemsByPath = new Map();\n\t\tthis._logger = (options.logger ?? new NullLogger()) as Logger;\n\t\tthis._cache = (options.cache ||\n\t\t\tnew DiscoveryCache<T>({ maxSize: 50, ttl: 300000 })) as DiscoveryCache<T>;\n\t\tthis._searchDirs = (options.searchDirs ?? []) as string[];\n\t}\n\n\t/**\n\t * Internal logging method.\n\t * @param message - The message to log\n\t * @param meta - Optional metadata\n\t */\n\tprotected log(message: string, meta?: Record<string, unknown>): void {\n\t\tthis._logger.info(message, meta);\n\t}\n\n\t/**\n\t * Adds an item to the registry.\n\t *\n\t * @param item - The item to add\n\t * @throws If item already exists or name is invalid\n\t */\n\tpublic add(item: T): void {\n\t\tif (!item.name) {\n\t\t\tthrow this._createInvalidError(`${this._entityName} must have a valid name`);\n\t\t}\n\t\tif (this._items.has(item.name)) {\n\t\t\tthrow this._createDuplicateError(item.name);\n\t\t}\n\t\tthis._items.set(item.name, item);\n\t\tthis._manualItems.set(item.name, item);\n\t\tthis.log(`Added ${this._entityName}: ${item.name}`, { [`${this._entityName}Name`]: item.name });\n\t\t// Invalidate cache when adding a new item\n\t\tthis._cache?.invalidate('all');\n\t}\n\n\t/**\n\t * Removes an item from the registry.\n\t *\n\t * @param name - The name of the item to remove\n\t * @throws If item not found\n\t */\n\tpublic remove(name: string): void {\n\t\tif (!this._items.has(name)) {\n\t\t\tthrow this._createNotFoundError(name, 'remove');\n\t\t}\n\t\tthis._items.delete(name);\n\t\tthis._manualItems.delete(name);\n\t\tfor (const [filePath, item] of this._discoveredItemsByPath) {\n\t\t\tif (item.name === name) this._discoveredItemsByPath.delete(filePath);\n\t\t}\n\t\tthis.log(`Removed ${this._entityName}: ${name}`, { [`${this._entityName}Name`]: name });\n\t\t// Invalidate cache when removing an item\n\t\tthis._cache?.invalidate('all');\n\t\tthis._cache?.invalidate(name);\n\t}\n\n\t/**\n\t * Updates an existing item with partial data.\n\t *\n\t * @param name - The name of the item to update\n\t * @param updates - Partial item data with fields to update\n\t * @throws If item not found\n\t */\n\tpublic update(name: string, updates: Partial<T>): void {\n\t\tif (!this._items.has(name)) {\n\t\t\tthrow this._createNotFoundError(name, 'update');\n\t\t}\n\t\tconst existing = this._items.get(name)!;\n\t\tconst updated = { ...existing, ...updates };\n\t\tthis._items.set(name, updated);\n\t\tif (this._manualItems.has(name)) this._manualItems.set(name, updated);\n\t\tfor (const [filePath, item] of this._discoveredItemsByPath) {\n\t\t\tif (item.name === name) this._discoveredItemsByPath.set(filePath, updated);\n\t\t}\n\t\tthis.log(`Updated ${this._entityName}: ${name}`, { [`${this._entityName}Name`]: name });\n\t\t// Invalidate cache when updating an item\n\t\tthis._cache?.invalidate('all');\n\t\tthis._cache?.invalidate(name);\n\t}\n\n\t/**\n\t * Gets an item by name.\n\t *\n\t * @param name - The name of the item to get\n\t * @returns The item if found, undefined otherwise\n\t */\n\tpublic get(name: string): T | undefined {\n\t\treturn this._items.get(name);\n\t}\n\n\t/**\n\t * Gets all items as an array.\n\t *\n\t * Uses cache if available for performance.\n\t *\n\t * @returns An array of all registered items\n\t */\n\tpublic getAll(): T[] {\n\t\t// Check cache first\n\t\tif (this._cache) {\n\t\t\tconst cached = this._cache.get('all');\n\t\t\tif (cached) {\n\t\t\t\treturn cached;\n\t\t\t}\n\t\t}\n\t\t// Get from storage\n\t\tconst items = Array.from(this._items.values());\n\t\t// Cache the result\n\t\tthis._cache?.set('all', items);\n\t\treturn items;\n\t}\n\n\t/**\n\t * Checks if an item exists in the registry.\n\t *\n\t * @param name - The name of the item to check\n\t * @returns true if the item exists, false otherwise\n\t */\n\tpublic has(name: string): boolean {\n\t\treturn this._items.has(name);\n\t}\n\n\t/**\n\t * Gets all item names as an array.\n\t *\n\t * @returns An array of item names\n\t */\n\tpublic getNames(): string[] {\n\t\treturn Array.from(this._items.keys());\n\t}\n\n\t/**\n\t * Clears all items from the registry.\n\t */\n\tpublic clear(): void {\n\t\tthis._items.clear();\n\t\tthis._manualItems.clear();\n\t\tthis._discoveredItemsByPath.clear();\n\t\tthis.log(`Cleared all ${this._entityName}s`);\n\t\t// Invalidate cache when clearing all items\n\t\tthis._cache?.clear();\n\t}\n\n\t/**\n\t * Gets the number of items in the registry.\n\t *\n\t * @returns The count of registered items\n\t */\n\tpublic size(): number {\n\t\treturn this._items.size;\n\t}\n\n\t/**\n\t * Asynchronously discovers items from the configured directories.\n\t *\n\t * Multiple concurrent calls share the same discovery promise.\n\t * Subsequent calls return cached results if discovery has already completed.\n\t *\n\t * @returns A Promise resolving to the number of items discovered\n\t */\n\tpublic async discoverAsync(): Promise<number> {\n\t\tif (this._discoveryPromise) {\n\t\t\treturn this._discoveryPromise;\n\t\t}\n\n\t\tif (this._discovered) {\n\t\t\tconst cached = this._cache.get('all');\n\t\t\treturn cached?.length ?? 0;\n\t\t}\n\n\t\treturn this._beginDiscovery();\n\t}\n\n\t/**\n\t * Re-scans configured directories and atomically reconciles discovered items.\n\t *\n\t * Calls made during an active scan share its promise and request at most one\n\t * follow-up pass, ensuring an event that arrives mid-scan is not lost.\n\t *\n\t * @returns A Promise resolving to the number of discovered filesystem items\n\t */\n\tpublic async refreshAsync(): Promise<number> {\n\t\tthis._refreshRequested = true;\n\t\treturn this._discoveryPromise ?? this._beginDiscovery();\n\t}\n\n\tprivate _beginDiscovery(): Promise<number> {\n\t\tconst operation = this._runDiscoveryLoop();\n\t\tthis._discoveryPromise = operation;\n\t\tconst clearOperation = (): void => {\n\t\t\tif (this._discoveryPromise === operation) this._discoveryPromise = null;\n\t\t};\n\t\toperation.then(clearOperation, clearOperation);\n\t\treturn operation;\n\t}\n\n\tprivate async _runDiscoveryLoop(): Promise<number> {\n\t\tthis._refreshRequested = false;\n\t\tlet count = await this._performDiscovery();\n\t\twhile (this._refreshRequested) {\n\t\t\tthis._refreshRequested = false;\n\t\t\tcount = await this._performDiscovery();\n\t\t}\n\t\treturn count;\n\t}\n\n\t/**\n\t * Performs the actual discovery operation.\n\t *\n\t * Scans configured directories for item files, parses their frontmatter,\n\t * and adds valid items to the registry.\n\t *\n\t * @returns A Promise resolving to the number of items discovered\n\t */\n\tprotected async _performDiscovery(): Promise<number> {\n\t\tconst discoveredItems = new Map<string, T>();\n\t\tconst claimedNames = new Set(this._manualItems.keys());\n\n\t\tfor (const dir of this._searchDirs) {\n\t\t\ttry {\n\t\t\t\tif (!existsSync(dir)) {\n\t\t\t\t\tcontinue;\n\t\t\t\t}\n\n\t\t\t\tconst entries = await readdir(dir, { withFileTypes: true });\n\t\t\t\tfor (const entry of entries) {\n\t\t\t\t\tif (this._shouldSkipFile(entry.name)) {\n\t\t\t\t\t\tcontinue;\n\t\t\t\t\t}\n\n\t\t\t\t\tif (entry.isFile() && this._fileExtensions.some((ext) => entry.name.endsWith(ext))) {\n\t\t\t\t\t\tconst filePath = join(dir, entry.name);\n\t\t\t\t\t\ttry {\n\t\t\t\t\t\t\tconst content = await readFile(filePath, 'utf-8');\n\t\t\t\t\t\t\tconst parsed = this._parseFrontmatter(content);\n\t\t\t\t\t\t\tif (parsed._error) {\n\t\t\t\t\t\t\t\tthis._retainLastKnownGood(filePath, parsed._error, discoveredItems, claimedNames);\n\t\t\t\t\t\t\t\tcontinue;\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\tif (parsed.name) {\n\t\t\t\t\t\t\t\tconst item = this._buildItem(parsed);\n\t\t\t\t\t\t\t\tif (item && !claimedNames.has(item.name)) {\n\t\t\t\t\t\t\t\t\tdiscoveredItems.set(filePath, item);\n\t\t\t\t\t\t\t\t\tclaimedNames.add(item.name);\n\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t} catch (readError) {\n\t\t\t\t\t\t\tthis._retainLastKnownGood(\n\t\t\t\t\t\t\t\tfilePath,\n\t\t\t\t\t\t\t\tgetErrorMessage(readError),\n\t\t\t\t\t\t\t\tdiscoveredItems,\n\t\t\t\t\t\t\t\tclaimedNames\n\t\t\t\t\t\t\t);\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t} catch (error) {\n\t\t\t\tthis._logger.warn(`Failed to scan ${this._entityName} directory`, {\n\t\t\t\t\tdirectory: dir,\n\t\t\t\t\terror: getErrorMessage(error),\n\t\t\t\t});\n\t\t\t\tthis._retainDirectory(dir, discoveredItems, claimedNames);\n\t\t\t}\n\t\t}\n\n\t\tthis._discoveredItemsByPath = discoveredItems;\n\t\tthis._items = new Map(this._manualItems);\n\t\tfor (const item of discoveredItems.values()) {\n\t\t\tif (!this._items.has(item.name)) this._items.set(item.name, item);\n\t\t}\n\t\tthis._discovered = true;\n\t\tthis._cache.clear();\n\t\tthis._cache.set('all', Array.from(this._items.values()));\n\t\tthis.log(`Discovery complete: found ${discoveredItems.size} ${this._entityName}s`, {\n\t\t\tdiscoveredCount: discoveredItems.size,\n\t\t});\n\t\treturn discoveredItems.size;\n\t}\n\n\tprivate _retainLastKnownGood(\n\t\tfilePath: string,\n\t\treason: string,\n\t\tdiscoveredItems: Map<string, T>,\n\t\tclaimedNames: Set<string>\n\t): void {\n\t\tconst previous = this._discoveredItemsByPath.get(filePath);\n\t\tif (previous && !claimedNames.has(previous.name)) {\n\t\t\tdiscoveredItems.set(filePath, previous);\n\t\t\tclaimedNames.add(previous.name);\n\t\t}\n\t\tthis._logger.warn(`Invalid ${this._entityName} discovery file`, {\n\t\t\tfilePath,\n\t\t\treason,\n\t\t\tretainedLastKnownGood: previous !== undefined,\n\t\t});\n\t}\n\n\tprivate _retainDirectory(\n\t\tdirectory: string,\n\t\tdiscoveredItems: Map<string, T>,\n\t\tclaimedNames: Set<string>\n\t): void {\n\t\tfor (const [filePath, item] of this._discoveredItemsByPath) {\n\t\t\tif (dirname(filePath) === directory && !claimedNames.has(item.name)) {\n\t\t\t\tdiscoveredItems.set(filePath, item);\n\t\t\t\tclaimedNames.add(item.name);\n\t\t\t}\n\t\t}\n\t}\n\n\t/**\n\t * Parses YAML frontmatter from file content.\n\t *\n\t * This is a shared utility for subclasses that parse YAML frontmatter.\n\t *\n\t * @param content - The file content to parse\n\t * @returns The parsed YAML object, or null if no frontmatter found\n\t */\n\tprotected _extractFrontmatter(content: string): Record<string, unknown> | null {\n\t\tconst match = content.match(/^---\\n([\\s\\S]+?)\\n---/);\n\t\tif (!match) {\n\t\t\treturn null;\n\t\t}\n\t\treturn parseYaml(match[1]!) as Record<string, unknown>;\n\t}\n\n\t/**\n\t * Sets items from an external source.\n\t *\n\t * Clears existing items and adds new ones from the provided array.\n\t *\n\t * @param items - Array of items from an external source\n\t */\n\tpublic setAll(items: T[]): void {\n\t\tthis.clear();\n\t\tfor (const item of items) {\n\t\t\ttry {\n\t\t\t\tthis.add(item);\n\t\t\t} catch (error) {\n\t\t\t\tthis.log(`Error adding ${this._entityName} '${item.name}':`, {\n\t\t\t\t\t[`${this._entityName}Name`]: item.name,\n\t\t\t\t\terror: getErrorMessage(error),\n\t\t\t\t});\n\t\t\t}\n\t\t}\n\t\tthis.log(`Set ${items.length} ${this._entityName}s from external source`, {\n\t\t\t[`${this._entityName}Count`]: items.length,\n\t\t});\n\t}\n}\n"],"names":["BaseRegistry","options","Map","NullLogger","DiscoveryCache","message","meta","item","name","filePath","updates","existing","updated","cached","items","Array","operation","clearOperation","count","discoveredItems","claimedNames","Set","dir","existsSync","entries","readdir","entry","ext","join","content","readFile","parsed","readError","getErrorMessage","error","reason","previous","undefined","directory","dirname","match","parseYaml"],"mappings":"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"}
1
+ {"version":3,"file":"registry/BaseRegistry.js","sources":["../../src/registry/BaseRegistry.ts"],"sourcesContent":["/**\n * Base registry providing shared CRUD, caching, and discovery logic.\n *\n * This abstract generic class extracts the common patterns from `ToolRegistry`\n * and `SkillRegistry` into a single reusable base. Subclasses only need to\n * implement item-specific parsing, file filtering, and error construction.\n *\n * @template T - The registry item type (must have a `name` property)\n * @module registry\n */\n\nimport { existsSync } from 'node:fs';\nimport { readdir, readFile } from 'node:fs/promises';\nimport { dirname, join } from 'node:path';\nimport { parse as parseYaml } from 'yaml';\nimport { DiscoveryCache } from '../cache/DiscoveryCache.js';\nimport { NullLogger } from '../logger/NullLogger.js';\nimport type { Logger } from '../logger/StructuredLogger.js';\nimport { getErrorMessage } from '../errors.js';\n\n/**\n * Configuration options for creating a `BaseRegistry` instance.\n */\nexport interface BaseRegistryOptions {\n\t/** Optional logger for diagnostics. */\n\tlogger?: Logger;\n\n\t/** Optional cache for lookups. */\n\tcache?: DiscoveryCache<{ name: string }>;\n\n\t/**\n\t * Directory paths to search for items.\n\t */\n\tsearchDirs?: string[];\n\n\t/**\n\t * Enable lazy discovery (discover on first access instead of startup).\n\t * @default false\n\t */\n\tlazyDiscovery?: boolean;\n}\n\ninterface DiscoveryWarning {\n\treadonly message: string;\n\treadonly meta: Record<string, unknown>;\n}\n\ninterface DiscoveryScan<T> {\n\treadonly itemsByPath: Map<string, T>;\n\treadonly claimedNames: Set<string>;\n\treadonly previousItemsByPath: ReadonlyMap<string, T>;\n\treadonly warnings: DiscoveryWarning[];\n}\n\n/**\n * Abstract base registry for managing named items with discovery and caching.\n *\n * Provides shared CRUD operations, filesystem discovery with deduplication,\n * and optional LRU caching. Subclasses implement item-specific parsing logic\n * and error construction.\n *\n * @template T - The registry item type (must have a `name` property)\n */\nexport abstract class BaseRegistry<T extends { name: string }> {\n\t/** Internal storage for items indexed by name. */\n\tprotected _items: Map<string, T>;\n\tprivate _manualItems: Map<string, T>;\n\tprivate _discoveredItemsByPath: Map<string, T>;\n\n\t/** Logger for diagnostics. */\n\tprotected _logger: Logger;\n\n\t/** Optional cache for lookups. */\n\tprotected _cache: DiscoveryCache<T>;\n\n\t/** Directory paths to search for items. */\n\tprotected _searchDirs: string[];\n\n\t/** Whether discovery has been performed. */\n\tprotected _discovered: boolean = false;\n\n\t/** Promise for in-progress discovery (null if not in progress). */\n\tprotected _discoveryPromise: Promise<number> | null = null;\n\tprivate _activeDiscoveryEpoch: number | null = null;\n\tprivate _queuedRefreshEpoch: number | null = null;\n\tprivate _replacementEpoch = 0;\n\tprivate _discoveredCount = 0;\n\n\t/** File extensions to match during discovery. */\n\tprotected abstract readonly _fileExtensions: string[];\n\n\t/**\n\t * Creates an error for invalid item data.\n\t * @param reason - The reason for the validation failure\n\t */\n\tprotected abstract _createInvalidError(reason: string): Error;\n\n\t/**\n\t * Creates an error for duplicate items.\n\t * @param name - The name of the duplicate item\n\t */\n\tprotected abstract _createDuplicateError(name: string): Error;\n\n\t/**\n\t * Creates an error for items not found.\n\t * @param name - The name of the missing item\n\t * @param action - The action that was attempted\n\t */\n\tprotected abstract _createNotFoundError(name: string, action: string): Error;\n\n\t/**\n\t * Parses frontmatter content into a partial item.\n\t * @param content - The file content to parse\n\t * @returns A partial item, with an `_error` property if parsing failed\n\t */\n\tprotected abstract _parseFrontmatter(content: string): Partial<T> & { _error?: string };\n\n\t/**\n\t * Determines whether a file should be skipped during discovery.\n\t * @param fileName - The name of the file to check\n\t * @returns true if the file should be skipped\n\t */\n\tprotected abstract _shouldSkipFile(fileName: string): boolean;\n\n\t/**\n\t * Constructs a complete item from parsed frontmatter data.\n\t * Returns null if the parsed data is insufficient.\n\t * @param parsed - The parsed frontmatter data\n\t * @returns A complete item, or null if data is insufficient\n\t */\n\tprotected abstract _buildItem(parsed: Partial<T>): T | null;\n\n\t/**\n\t * The entity name used in log messages (e.g., 'tool', 'skill').\n\t */\n\tprotected abstract readonly _entityName: string;\n\n\tconstructor(options: BaseRegistryOptions) {\n\t\tthis._items = new Map();\n\t\tthis._manualItems = new Map();\n\t\tthis._discoveredItemsByPath = new Map();\n\t\tthis._logger = (options.logger ?? new NullLogger()) as Logger;\n\t\tthis._cache = (options.cache ||\n\t\t\tnew DiscoveryCache<T>({ maxSize: 50, ttl: 300000 })) as DiscoveryCache<T>;\n\t\tthis._searchDirs = (options.searchDirs ?? []) as string[];\n\t}\n\n\t/**\n\t * Internal logging method.\n\t * @param message - The message to log\n\t * @param meta - Optional metadata\n\t */\n\tprotected log(message: string, meta?: Record<string, unknown>): void {\n\t\tthis._logger.info(message, meta);\n\t}\n\n\t/**\n\t * Adds an item to the registry.\n\t *\n\t * @param item - The item to add\n\t * @throws If item already exists or name is invalid\n\t */\n\tpublic add(item: T): void {\n\t\tif (!item.name) {\n\t\t\tthrow this._createInvalidError(`${this._entityName} must have a valid name`);\n\t\t}\n\t\tif (this._items.has(item.name)) {\n\t\t\tthrow this._createDuplicateError(item.name);\n\t\t}\n\t\tthis._items.set(item.name, item);\n\t\tthis._manualItems.set(item.name, item);\n\t\tthis.log(`Added ${this._entityName}: ${item.name}`, { [`${this._entityName}Name`]: item.name });\n\t\t// Invalidate cache when adding a new item\n\t\tthis._cache?.invalidate('all');\n\t}\n\n\t/**\n\t * Removes an item from the registry.\n\t *\n\t * @param name - The name of the item to remove\n\t * @throws If item not found\n\t */\n\tpublic remove(name: string): void {\n\t\tif (!this._items.has(name)) {\n\t\t\tthrow this._createNotFoundError(name, 'remove');\n\t\t}\n\t\tconst removedManualItem = this._manualItems.delete(name);\n\t\tif (!removedManualItem) {\n\t\t\tfor (const [filePath, item] of this._discoveredItemsByPath) {\n\t\t\t\tif (item.name === name) this._discoveredItemsByPath.delete(filePath);\n\t\t\t}\n\t\t}\n\t\tthis._rebuildVisibleItems();\n\t\tthis.log(`Removed ${this._entityName}: ${name}`, { [`${this._entityName}Name`]: name });\n\t\t// Invalidate cache when removing an item\n\t\tthis._cache?.invalidate('all');\n\t\tthis._cache?.invalidate(name);\n\t}\n\n\t/**\n\t * Updates an existing item with partial data.\n\t *\n\t * @param name - The name of the item to update\n\t * @param updates - Partial item data with fields to update\n\t * @throws If item not found\n\t */\n\tpublic update(name: string, updates: Partial<T>): void {\n\t\tif (!this._items.has(name)) {\n\t\t\tthrow this._createNotFoundError(name, 'update');\n\t\t}\n\t\tconst isManualItem = this._manualItems.has(name);\n\t\tconst existing = this._items.get(name)!;\n\t\tconst updated = { ...existing, ...updates, name };\n\t\tthis._items.set(name, updated);\n\t\tif (isManualItem) {\n\t\t\tthis._manualItems.set(name, updated);\n\t\t} else {\n\t\t\tfor (const [filePath, item] of this._discoveredItemsByPath) {\n\t\t\t\tif (item.name === name) this._discoveredItemsByPath.set(filePath, updated);\n\t\t\t}\n\t\t}\n\t\tthis.log(`Updated ${this._entityName}: ${name}`, { [`${this._entityName}Name`]: name });\n\t\t// Invalidate cache when updating an item\n\t\tthis._cache?.invalidate('all');\n\t\tthis._cache?.invalidate(name);\n\t}\n\n\t/**\n\t * Gets an item by name.\n\t *\n\t * @param name - The name of the item to get\n\t * @returns The item if found, undefined otherwise\n\t */\n\tpublic get(name: string): T | undefined {\n\t\treturn this._items.get(name);\n\t}\n\n\t/**\n\t * Gets all items as an array.\n\t *\n\t * Uses cache if available for performance.\n\t *\n\t * @returns An array of all registered items\n\t */\n\tpublic getAll(): T[] {\n\t\t// Check cache first\n\t\tif (this._cache) {\n\t\t\tconst cached = this._cache.get('all');\n\t\t\tif (cached) {\n\t\t\t\treturn cached;\n\t\t\t}\n\t\t}\n\t\t// Get from storage\n\t\tconst items = Array.from(this._items.values());\n\t\t// Cache the result\n\t\tthis._cache?.set('all', items);\n\t\treturn items;\n\t}\n\n\t/**\n\t * Checks if an item exists in the registry.\n\t *\n\t * @param name - The name of the item to check\n\t * @returns true if the item exists, false otherwise\n\t */\n\tpublic has(name: string): boolean {\n\t\treturn this._items.has(name);\n\t}\n\n\t/**\n\t * Gets all item names as an array.\n\t *\n\t * @returns An array of item names\n\t */\n\tpublic getNames(): string[] {\n\t\treturn Array.from(this._items.keys());\n\t}\n\n\t/**\n\t * Clears all items from the registry.\n\t */\n\tpublic clear(): void {\n\t\tthis._beginReplacement();\n\t\tthis.log(`Cleared all ${this._entityName}s`);\n\t}\n\n\t/**\n\t * Gets the number of items in the registry.\n\t *\n\t * @returns The count of registered items\n\t */\n\tpublic size(): number {\n\t\treturn this._items.size;\n\t}\n\n\t/**\n\t * Asynchronously discovers items from the configured directories.\n\t *\n\t * Multiple concurrent calls share the same discovery promise.\n\t * Subsequent calls return cached results if discovery has already completed.\n\t *\n\t * @returns A Promise resolving to the number of items discovered\n\t */\n\tpublic async discoverAsync(): Promise<number> {\n\t\tif (this._discoveryPromise) {\n\t\t\tif (\n\t\t\t\t!this._discovered &&\n\t\t\t\tthis._activeDiscoveryEpoch !== this._replacementEpoch\n\t\t\t) {\n\t\t\t\tthis._queuedRefreshEpoch = this._replacementEpoch;\n\t\t\t}\n\t\t\treturn this._discoveryPromise;\n\t\t}\n\n\t\tif (this._discovered) {\n\t\t\treturn this._discoveredCount;\n\t\t}\n\n\t\treturn this._beginDiscovery();\n\t}\n\n\t/**\n\t * Re-scans configured directories and atomically reconciles discovered items.\n\t *\n\t * Calls made during an active scan share its promise and request at most one\n\t * follow-up pass, ensuring an event that arrives mid-scan is not lost.\n\t *\n\t * @returns A Promise resolving to the number of discovered filesystem items\n\t */\n\tpublic async refreshAsync(): Promise<number> {\n\t\tif (this._discoveryPromise) {\n\t\t\tthis._queuedRefreshEpoch = this._replacementEpoch;\n\t\t\treturn this._discoveryPromise;\n\t\t}\n\t\treturn this._beginDiscovery();\n\t}\n\n\tprivate _beginDiscovery(): Promise<number> {\n\t\tconst operation = this._runDiscoveryLoop();\n\t\tthis._discoveryPromise = operation;\n\t\treturn operation;\n\t}\n\n\tprivate async _runDiscoveryLoop(): Promise<number> {\n\t\tlet passEpoch = this._replacementEpoch;\n\t\ttry {\n\t\t\twhile (true) {\n\t\t\t\tthis._activeDiscoveryEpoch = passEpoch;\n\t\t\t\tlet count: number;\n\t\t\t\ttry {\n\t\t\t\t\tcount = await this._performDiscovery(passEpoch);\n\t\t\t\t} finally {\n\t\t\t\t\tthis._activeDiscoveryEpoch = null;\n\t\t\t\t}\n\n\t\t\t\tconst queuedEpoch = this._queuedRefreshEpoch;\n\t\t\t\tthis._queuedRefreshEpoch = null;\n\t\t\t\tif (queuedEpoch === null) return count;\n\t\t\t\tpassEpoch = queuedEpoch;\n\t\t\t}\n\t\t} finally {\n\t\t\tthis._discoveryPromise = null;\n\t\t}\n\t}\n\n\t/**\n\t * Performs the actual discovery operation.\n\t *\n\t * Scans configured directories for item files, parses their frontmatter,\n\t * and adds valid items to the registry.\n\t *\n\t * @returns A Promise resolving to the number of items discovered\n\t */\n\tprotected async _performDiscovery(epoch = this._replacementEpoch): Promise<number> {\n\t\tconst scan: DiscoveryScan<T> = {\n\t\t\titemsByPath: new Map(),\n\t\t\tclaimedNames: new Set(),\n\t\t\tpreviousItemsByPath: new Map(this._discoveredItemsByPath),\n\t\t\twarnings: [],\n\t\t};\n\t\tfor (const dir of this._searchDirs) {\n\t\t\tawait this._scanDirectory(dir, scan);\n\t\t}\n\t\treturn this._publishDiscovery(epoch, scan);\n\t}\n\n\tprivate async _scanDirectory(directory: string, scan: DiscoveryScan<T>): Promise<void> {\n\t\ttry {\n\t\t\tif (!existsSync(directory)) return;\n\t\t\tconst entries = await readdir(directory, { withFileTypes: true });\n\t\t\tfor (const entry of entries) {\n\t\t\t\tif (this._shouldSkipFile(entry.name) || !entry.isFile()) continue;\n\t\t\t\tif (!this._fileExtensions.some((extension) => entry.name.endsWith(extension))) continue;\n\t\t\t\tawait this._scanFile(join(directory, entry.name), scan);\n\t\t\t}\n\t\t} catch (error) {\n\t\t\tscan.warnings.push({\n\t\t\t\tmessage: `Failed to scan ${this._entityName} directory`,\n\t\t\t\tmeta: { directory, error: getErrorMessage(error) },\n\t\t\t});\n\t\t\tthis._retainDirectory(directory, scan);\n\t\t}\n\t}\n\n\tprivate async _scanFile(filePath: string, scan: DiscoveryScan<T>): Promise<void> {\n\t\ttry {\n\t\t\tconst content = await readFile(filePath, 'utf-8');\n\t\t\tconst parsed = this._parseFrontmatter(content);\n\t\t\tif (parsed._error) {\n\t\t\t\tthis._retainLastKnownGood(filePath, parsed._error, scan);\n\t\t\t\treturn;\n\t\t\t}\n\t\t\tif (!parsed.name) return;\n\t\t\tconst item = this._buildItem(parsed);\n\t\t\tif (item && !scan.claimedNames.has(item.name)) {\n\t\t\t\tscan.itemsByPath.set(filePath, item);\n\t\t\t\tscan.claimedNames.add(item.name);\n\t\t\t}\n\t\t} catch (error) {\n\t\t\tthis._retainLastKnownGood(filePath, getErrorMessage(error), scan);\n\t\t}\n\t}\n\n\tprivate _retainLastKnownGood(filePath: string, reason: string, scan: DiscoveryScan<T>): void {\n\t\tconst previous = scan.previousItemsByPath.get(filePath);\n\t\tif (previous && !scan.claimedNames.has(previous.name)) {\n\t\t\tscan.itemsByPath.set(filePath, previous);\n\t\t\tscan.claimedNames.add(previous.name);\n\t\t}\n\t\tscan.warnings.push({\n\t\t\tmessage: `Invalid ${this._entityName} discovery file`,\n\t\t\tmeta: { filePath, reason, retainedLastKnownGood: previous !== undefined },\n\t\t});\n\t}\n\n\tprivate _retainDirectory(directory: string, scan: DiscoveryScan<T>): void {\n\t\tfor (const [filePath, item] of scan.previousItemsByPath) {\n\t\t\tif (dirname(filePath) === directory && !scan.claimedNames.has(item.name)) {\n\t\t\t\tscan.itemsByPath.set(filePath, item);\n\t\t\t\tscan.claimedNames.add(item.name);\n\t\t\t}\n\t\t}\n\t}\n\n\tprivate _publishDiscovery(epoch: number, scan: DiscoveryScan<T>): number {\n\t\tif (epoch !== this._replacementEpoch) return this._discoveredCount;\n\n\t\tthis._discoveredItemsByPath = scan.itemsByPath;\n\t\tthis._rebuildVisibleItems();\n\t\tthis._discovered = true;\n\t\tthis._cache.clear();\n\t\tthis._cache.set('all', Array.from(this._items.values()));\n\t\tfor (const warning of scan.warnings) this._logger.warn(warning.message, warning.meta);\n\t\tthis.log(`Discovery complete: found ${this._discoveredCount} ${this._entityName}s`, {\n\t\t\tdiscoveredCount: this._discoveredCount,\n\t\t});\n\t\treturn this._discoveredCount;\n\t}\n\n\tprivate _rebuildVisibleItems(): void {\n\t\tconst visibleItems = new Map(this._manualItems);\n\t\tlet visibleDiscoveredCount = 0;\n\t\tfor (const item of this._discoveredItemsByPath.values()) {\n\t\t\tif (visibleItems.has(item.name)) continue;\n\t\t\tvisibleItems.set(item.name, item);\n\t\t\tvisibleDiscoveredCount++;\n\t\t}\n\t\tthis._items = visibleItems;\n\t\tthis._discoveredCount = visibleDiscoveredCount;\n\t}\n\n\tprivate _beginReplacement(): void {\n\t\tthis._replacementEpoch++;\n\t\tthis._queuedRefreshEpoch = null;\n\t\tthis._items.clear();\n\t\tthis._manualItems.clear();\n\t\tthis._discoveredItemsByPath.clear();\n\t\tthis._discovered = false;\n\t\tthis._discoveredCount = 0;\n\t\tthis._cache.clear();\n\t}\n\n\t/**\n\t * Parses YAML frontmatter from file content.\n\t *\n\t * This is a shared utility for subclasses that parse YAML frontmatter.\n\t *\n\t * @param content - The file content to parse\n\t * @returns The parsed YAML object, or null if no frontmatter found\n\t */\n\tprotected _extractFrontmatter(content: string): Record<string, unknown> | null {\n\t\tconst match = content.match(/^---\\n([\\s\\S]+?)\\n---/);\n\t\tif (!match) {\n\t\t\treturn null;\n\t\t}\n\t\treturn parseYaml(match[1]!) as Record<string, unknown>;\n\t}\n\n\t/**\n\t * Sets items from an external source.\n\t *\n\t * Clears existing items and adds new ones from the provided array.\n\t *\n\t * @param items - Array of items from an external source\n\t */\n\tpublic setAll(items: T[]): void {\n\t\tthis._beginReplacement();\n\t\tfor (const item of items) {\n\t\t\ttry {\n\t\t\t\tthis.add(item);\n\t\t\t} catch (error) {\n\t\t\t\tthis.log(`Error adding ${this._entityName} '${item.name}':`, {\n\t\t\t\t\t[`${this._entityName}Name`]: item.name,\n\t\t\t\t\terror: getErrorMessage(error),\n\t\t\t\t});\n\t\t\t}\n\t\t}\n\t\tthis.log(`Set ${items.length} ${this._entityName}s from external source`, {\n\t\t\t[`${this._entityName}Count`]: items.length,\n\t\t});\n\t}\n}\n"],"names":["BaseRegistry","options","Map","NullLogger","DiscoveryCache","message","meta","item","name","removedManualItem","filePath","updates","isManualItem","existing","updated","cached","items","Array","operation","passEpoch","count","queuedEpoch","epoch","scan","Set","dir","directory","existsSync","entries","readdir","entry","extension","join","error","getErrorMessage","content","readFile","parsed","reason","previous","undefined","dirname","warning","visibleItems","visibleDiscoveredCount","match","parseYaml"],"mappings":"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"}
@@ -43,8 +43,7 @@ export interface SkillRegistryOptions {
43
43
  /**
44
44
  * Registry for managing Claude Code skill operations.
45
45
  *
46
- * Extends `BaseRegistry<Skill>` with skill-specific frontmatter parsing
47
- * and backward-compatible aliases (`addSkill`, etc.).
46
+ * Extends `BaseRegistry<Skill>` with skill-specific frontmatter parsing.
48
47
  */
49
48
  export declare class SkillRegistry extends BaseRegistry<Skill> {
50
49
  protected readonly _fileExtensions: string[];
@@ -58,10 +57,5 @@ export declare class SkillRegistry extends BaseRegistry<Skill> {
58
57
  _error?: string;
59
58
  };
60
59
  protected _buildItem(parsed: Partial<Skill>): Skill | null;
61
- addSkill(skill: Skill): void;
62
- updateSkill(name: string, updates: Partial<Skill>): void;
63
- hasSkill(name: string): boolean;
64
- getSkill(name: string): Skill | undefined;
65
- setSkills(skills: Skill[]): void;
66
60
  }
67
61
  //# sourceMappingURL=SkillRegistry.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"SkillRegistry.d.ts","sourceRoot":"","sources":["../../src/registry/SkillRegistry.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG;AAIH,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,4BAA4B,CAAC;AAEjE,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,+BAA+B,CAAC;AAC5D,OAAO,KAAK,EAAE,KAAK,EAAE,MAAM,mBAAmB,CAAC;AAC/C,OAAO,EAAE,YAAY,EAAE,MAAM,mBAAmB,CAAC;AAEjD;;;;;;;;;;;;GAYG;AACH,MAAM,WAAW,oBAAoB;IACpC,uCAAuC;IACvC,MAAM,CAAC,EAAE,MAAM,CAAC;IAEhB,wCAAwC;IACxC,KAAK,CAAC,EAAE,cAAc,CAAC,KAAK,CAAC,CAAC;IAE9B;;;OAGG;IACH,SAAS,CAAC,EAAE,MAAM,EAAE,CAAC;IAErB;;;OAGG;IACH,aAAa,CAAC,EAAE,OAAO,CAAC;CACxB;AAED;;;;;GAKG;AACH,qBAAa,aAAc,SAAQ,YAAY,CAAC,KAAK,CAAC;IACrD,mBAA4B,eAAe,WAA4B;IACvE,mBAA4B,WAAW,WAAW;gBAEtC,OAAO,GAAE,oBAAyB;cAgB3B,mBAAmB,CAAC,MAAM,EAAE,MAAM,GAAG,KAAK;cAI1C,qBAAqB,CAAC,IAAI,EAAE,MAAM,GAAG,KAAK;cAI1C,oBAAoB,CAAC,IAAI,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,GAAG,KAAK;cAMzD,eAAe,CAAC,QAAQ,EAAE,MAAM,GAAG,OAAO;cAI1C,iBAAiB,CAAC,OAAO,EAAE,MAAM,GAAG,OAAO,CAAC,KAAK,CAAC,GAAG;QAAE,MAAM,CAAC,EAAE,MAAM,CAAA;KAAE;cA6BxE,UAAU,CAAC,MAAM,EAAE,OAAO,CAAC,KAAK,CAAC,GAAG,KAAK,GAAG,IAAI;IAc5D,QAAQ,CAAC,KAAK,EAAE,KAAK,GAAG,IAAI;IAI5B,WAAW,CAAC,IAAI,EAAE,MAAM,EAAE,OAAO,EAAE,OAAO,CAAC,KAAK,CAAC,GAAG,IAAI;IAIxD,QAAQ,CAAC,IAAI,EAAE,MAAM,GAAG,OAAO;IAI/B,QAAQ,CAAC,IAAI,EAAE,MAAM,GAAG,KAAK,GAAG,SAAS;IAIzC,SAAS,CAAC,MAAM,EAAE,KAAK,EAAE,GAAG,IAAI;CAGvC"}
1
+ {"version":3,"file":"SkillRegistry.d.ts","sourceRoot":"","sources":["../../src/registry/SkillRegistry.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG;AAIH,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,4BAA4B,CAAC;AAEjE,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,+BAA+B,CAAC;AAC5D,OAAO,KAAK,EAAE,KAAK,EAAE,MAAM,mBAAmB,CAAC;AAC/C,OAAO,EAAE,YAAY,EAAE,MAAM,mBAAmB,CAAC;AAEjD;;;;;;;;;;;;GAYG;AACH,MAAM,WAAW,oBAAoB;IACpC,uCAAuC;IACvC,MAAM,CAAC,EAAE,MAAM,CAAC;IAEhB,wCAAwC;IACxC,KAAK,CAAC,EAAE,cAAc,CAAC,KAAK,CAAC,CAAC;IAE9B;;;OAGG;IACH,SAAS,CAAC,EAAE,MAAM,EAAE,CAAC;IAErB;;;OAGG;IACH,aAAa,CAAC,EAAE,OAAO,CAAC;CACxB;AAED;;;;GAIG;AACH,qBAAa,aAAc,SAAQ,YAAY,CAAC,KAAK,CAAC;IACrD,mBAA4B,eAAe,WAA4B;IACvE,mBAA4B,WAAW,WAAW;gBAEtC,OAAO,GAAE,oBAAyB;cAgB3B,mBAAmB,CAAC,MAAM,EAAE,MAAM,GAAG,KAAK;cAI1C,qBAAqB,CAAC,IAAI,EAAE,MAAM,GAAG,KAAK;cAI1C,oBAAoB,CAAC,IAAI,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,GAAG,KAAK;cAMzD,eAAe,CAAC,QAAQ,EAAE,MAAM,GAAG,OAAO;cAI1C,iBAAiB,CAAC,OAAO,EAAE,MAAM,GAAG,OAAO,CAAC,KAAK,CAAC,GAAG;QAAE,MAAM,CAAC,EAAE,MAAM,CAAA;KAAE;cA6BxE,UAAU,CAAC,MAAM,EAAE,OAAO,CAAC,KAAK,CAAC,GAAG,KAAK,GAAG,IAAI;CAWnE"}
@@ -66,21 +66,6 @@ class SkillRegistry extends BaseRegistry {
66
66
  allowed_tools: parsed.allowed_tools
67
67
  };
68
68
  }
69
- addSkill(skill) {
70
- this.add(skill);
71
- }
72
- updateSkill(name, updates) {
73
- this.update(name, updates);
74
- }
75
- hasSkill(name) {
76
- return this.has(name);
77
- }
78
- getSkill(name) {
79
- return this.get(name);
80
- }
81
- setSkills(skills) {
82
- this.setAll(skills);
83
- }
84
69
  }
85
70
  export { SkillRegistry };
86
71
 
@@ -1 +1 @@
1
- {"version":3,"file":"registry/SkillRegistry.js","sources":["../../src/registry/SkillRegistry.ts"],"sourcesContent":["/**\n * Skill registry for managing and discovering Claude Code skills.\n *\n * This module provides the `SkillRegistry` class which manages skill registration,\n * discovery from filesystem directories, and CRUD operations. Skills are higher-level\n * workflows that coordinate multiple tools and operations.\n *\n * @module registry\n */\n\nimport { homedir } from 'node:os';\nimport { join } from 'node:path';\nimport type { DiscoveryCache } from '../cache/DiscoveryCache.js';\nimport { DuplicateSkillError, InvalidSkillError, SkillNotFoundError } from '../errors.js';\nimport type { Logger } from '../logger/StructuredLogger.js';\nimport type { Skill } from '../types/skill.js';\nimport { BaseRegistry } from './BaseRegistry.js';\n\n/**\n * Configuration options for creating a `SkillRegistry` instance.\n *\n * @example\n * ```typescript\n * const options: SkillRegistryOptions = {\n * logger: new StructuredLogger({ context: 'SkillRegistry' }),\n * cache: new DiscoveryCache({ ttl: 300000, maxSize: 100 }),\n * skillDirs: ['./custom-skills', '~/.claude/skills'],\n * lazyDiscovery: true\n * };\n * ```\n */\nexport interface SkillRegistryOptions {\n\t/** Optional logger for diagnostics. */\n\tlogger?: Logger;\n\n\t/** Optional cache for skill lookups. */\n\tcache?: DiscoveryCache<Skill>;\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 * Enable lazy discovery (discover on first access instead of startup).\n\t * @default false\n\t */\n\tlazyDiscovery?: boolean;\n}\n\n/**\n * Registry for managing Claude Code skill operations.\n *\n * Extends `BaseRegistry<Skill>` with skill-specific frontmatter parsing\n * and backward-compatible aliases (`addSkill`, etc.).\n */\nexport class SkillRegistry extends BaseRegistry<Skill> {\n\tprotected override readonly _fileExtensions = ['.md', '.yml', '.yaml'];\n\tprotected override readonly _entityName = 'skill';\n\n\tconstructor(options: SkillRegistryOptions = {}) {\n\t\tsuper({\n\t\t\tlogger: options.logger,\n\t\t\tcache: options.cache,\n\t\t\tsearchDirs: options.skillDirs ?? [\n\t\t\t\t'.claude/skills',\n\t\t\t\tjoin(homedir(), '.claude/skills'),\n\t\t\t\t'.agents/skills',\n\t\t\t\tjoin(homedir(), '.agents/skills'),\n\t\t\t],\n\t\t\tlazyDiscovery: options.lazyDiscovery,\n\t\t});\n\t}\n\n\t// --- Error factories ---\n\n\tprotected override _createInvalidError(reason: string): Error {\n\t\treturn new InvalidSkillError(reason);\n\t}\n\n\tprotected override _createDuplicateError(name: string): Error {\n\t\treturn new DuplicateSkillError(name);\n\t}\n\n\tprotected override _createNotFoundError(name: string, action: string): Error {\n\t\treturn new SkillNotFoundError(name, action);\n\t}\n\n\t// --- Discovery ---\n\n\tprotected override _shouldSkipFile(fileName: string): boolean {\n\t\treturn fileName === '.DS_Store';\n\t}\n\n\tprotected override _parseFrontmatter(content: string): Partial<Skill> & { _error?: string } {\n\t\tconst frontmatter = this._extractFrontmatter(content);\n\t\tif (!frontmatter) {\n\t\t\treturn {};\n\t\t}\n\n\t\ttry {\n\t\t\tconst result: Partial<Skill> = {\n\t\t\t\tname: typeof frontmatter.name === 'string' ? frontmatter.name : undefined,\n\t\t\t\tdescription: typeof frontmatter.description === 'string' ? frontmatter.description : '',\n\t\t\t\tuser_invocable: frontmatter['user-invocable'] === true,\n\t\t\t\tallowed_tools: Array.isArray(frontmatter['allowed-tools'])\n\t\t\t\t\t? frontmatter['allowed-tools'].map(String)\n\t\t\t\t\t: undefined,\n\t\t\t};\n\n\t\t\tif (!result.name) {\n\t\t\t\treturn { _error: 'Missing required field: name' };\n\t\t\t}\n\n\t\t\treturn result;\n\t\t} catch (error) {\n\t\t\tthis.log('Error parsing YAML frontmatter:', {\n\t\t\t\terror: error instanceof Error ? error.message : String(error),\n\t\t\t});\n\t\t\treturn { _error: 'YAML parse error' };\n\t\t}\n\t}\n\n\tprotected override _buildItem(parsed: Partial<Skill>): Skill | null {\n\t\tif (!parsed.name) {\n\t\t\treturn null;\n\t\t}\n\t\treturn {\n\t\t\tname: parsed.name,\n\t\t\tdescription: parsed.description || '',\n\t\t\tuser_invocable: parsed.user_invocable ?? false,\n\t\t\tallowed_tools: parsed.allowed_tools,\n\t\t};\n\t}\n\n\t// --- Backward-compatible aliases ---\n\n\tpublic addSkill(skill: Skill): void {\n\t\tthis.add(skill);\n\t}\n\n\tpublic updateSkill(name: string, updates: Partial<Skill>): void {\n\t\tthis.update(name, updates);\n\t}\n\n\tpublic hasSkill(name: string): boolean {\n\t\treturn this.has(name);\n\t}\n\n\tpublic getSkill(name: string): Skill | undefined {\n\t\treturn this.get(name);\n\t}\n\n\tpublic setSkills(skills: Skill[]): void {\n\t\tthis.setAll(skills);\n\t}\n}\n"],"names":["SkillRegistry","BaseRegistry","options","join","homedir","reason","InvalidSkillError","name","DuplicateSkillError","action","SkillNotFoundError","fileName","content","frontmatter","result","undefined","Array","String","error","Error","parsed","skill","updates","skills"],"mappings":";;;;AAyDO,MAAMA,sBAAsBC;IACN,kBAAkB;QAAC;QAAO;QAAQ;KAAQ,CAAC;IAC3C,cAAc,QAAQ;IAElD,YAAYC,UAAgC,CAAC,CAAC,CAAE;QAC/C,KAAK,CAAC;YACL,QAAQA,QAAQ,MAAM;YACtB,OAAOA,QAAQ,KAAK;YACpB,YAAYA,QAAQ,SAAS,IAAI;gBAChC;gBACAC,KAAKC,WAAW;gBAChB;gBACAD,KAAKC,WAAW;aAChB;YACD,eAAeF,QAAQ,aAAa;QACrC;IACD;IAImB,oBAAoBG,MAAc,EAAS;QAC7D,OAAO,IAAIC,kBAAkBD;IAC9B;IAEmB,sBAAsBE,IAAY,EAAS;QAC7D,OAAO,IAAIC,oBAAoBD;IAChC;IAEmB,qBAAqBA,IAAY,EAAEE,MAAc,EAAS;QAC5E,OAAO,IAAIC,mBAAmBH,MAAME;IACrC;IAImB,gBAAgBE,QAAgB,EAAW;QAC7D,OAAOA,AAAa,gBAAbA;IACR;IAEmB,kBAAkBC,OAAe,EAAwC;QAC3F,MAAMC,cAAc,IAAI,CAAC,mBAAmB,CAACD;QAC7C,IAAI,CAACC,aACJ,OAAO,CAAC;QAGT,IAAI;YACH,MAAMC,SAAyB;gBAC9B,MAAM,AAA4B,YAA5B,OAAOD,YAAY,IAAI,GAAgBA,YAAY,IAAI,GAAGE;gBAChE,aAAa,AAAmC,YAAnC,OAAOF,YAAY,WAAW,GAAgBA,YAAY,WAAW,GAAG;gBACrF,gBAAgBA,AAAkC,SAAlCA,WAAW,CAAC,iBAAiB;gBAC7C,eAAeG,MAAM,OAAO,CAACH,WAAW,CAAC,gBAAgB,IACtDA,WAAW,CAAC,gBAAgB,CAAC,GAAG,CAACI,UACjCF;YACJ;YAEA,IAAI,CAACD,OAAO,IAAI,EACf,OAAO;gBAAE,QAAQ;YAA+B;YAGjD,OAAOA;QACR,EAAE,OAAOI,OAAO;YACf,IAAI,CAAC,GAAG,CAAC,mCAAmC;gBAC3C,OAAOA,iBAAiBC,QAAQD,MAAM,OAAO,GAAGD,OAAOC;YACxD;YACA,OAAO;gBAAE,QAAQ;YAAmB;QACrC;IACD;IAEmB,WAAWE,MAAsB,EAAgB;QACnE,IAAI,CAACA,OAAO,IAAI,EACf,OAAO;QAER,OAAO;YACN,MAAMA,OAAO,IAAI;YACjB,aAAaA,OAAO,WAAW,IAAI;YACnC,gBAAgBA,OAAO,cAAc,IAAI;YACzC,eAAeA,OAAO,aAAa;QACpC;IACD;IAIO,SAASC,KAAY,EAAQ;QACnC,IAAI,CAAC,GAAG,CAACA;IACV;IAEO,YAAYd,IAAY,EAAEe,OAAuB,EAAQ;QAC/D,IAAI,CAAC,MAAM,CAACf,MAAMe;IACnB;IAEO,SAASf,IAAY,EAAW;QACtC,OAAO,IAAI,CAAC,GAAG,CAACA;IACjB;IAEO,SAASA,IAAY,EAAqB;QAChD,OAAO,IAAI,CAAC,GAAG,CAACA;IACjB;IAEO,UAAUgB,MAAe,EAAQ;QACvC,IAAI,CAAC,MAAM,CAACA;IACb;AACD"}
1
+ {"version":3,"file":"registry/SkillRegistry.js","sources":["../../src/registry/SkillRegistry.ts"],"sourcesContent":["/**\n * Skill registry for managing and discovering Claude Code skills.\n *\n * This module provides the `SkillRegistry` class which manages skill registration,\n * discovery from filesystem directories, and CRUD operations. Skills are higher-level\n * workflows that coordinate multiple tools and operations.\n *\n * @module registry\n */\n\nimport { homedir } from 'node:os';\nimport { join } from 'node:path';\nimport type { DiscoveryCache } from '../cache/DiscoveryCache.js';\nimport { DuplicateSkillError, InvalidSkillError, SkillNotFoundError } from '../errors.js';\nimport type { Logger } from '../logger/StructuredLogger.js';\nimport type { Skill } from '../types/skill.js';\nimport { BaseRegistry } from './BaseRegistry.js';\n\n/**\n * Configuration options for creating a `SkillRegistry` instance.\n *\n * @example\n * ```typescript\n * const options: SkillRegistryOptions = {\n * logger: new StructuredLogger({ context: 'SkillRegistry' }),\n * cache: new DiscoveryCache({ ttl: 300000, maxSize: 100 }),\n * skillDirs: ['./custom-skills', '~/.claude/skills'],\n * lazyDiscovery: true\n * };\n * ```\n */\nexport interface SkillRegistryOptions {\n\t/** Optional logger for diagnostics. */\n\tlogger?: Logger;\n\n\t/** Optional cache for skill lookups. */\n\tcache?: DiscoveryCache<Skill>;\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 * Enable lazy discovery (discover on first access instead of startup).\n\t * @default false\n\t */\n\tlazyDiscovery?: boolean;\n}\n\n/**\n * Registry for managing Claude Code skill operations.\n *\n * Extends `BaseRegistry<Skill>` with skill-specific frontmatter parsing.\n */\nexport class SkillRegistry extends BaseRegistry<Skill> {\n\tprotected override readonly _fileExtensions = ['.md', '.yml', '.yaml'];\n\tprotected override readonly _entityName = 'skill';\n\n\tconstructor(options: SkillRegistryOptions = {}) {\n\t\tsuper({\n\t\t\tlogger: options.logger,\n\t\t\tcache: options.cache,\n\t\t\tsearchDirs: options.skillDirs ?? [\n\t\t\t\t'.claude/skills',\n\t\t\t\tjoin(homedir(), '.claude/skills'),\n\t\t\t\t'.agents/skills',\n\t\t\t\tjoin(homedir(), '.agents/skills'),\n\t\t\t],\n\t\t\tlazyDiscovery: options.lazyDiscovery,\n\t\t});\n\t}\n\n\t// --- Error factories ---\n\n\tprotected override _createInvalidError(reason: string): Error {\n\t\treturn new InvalidSkillError(reason);\n\t}\n\n\tprotected override _createDuplicateError(name: string): Error {\n\t\treturn new DuplicateSkillError(name);\n\t}\n\n\tprotected override _createNotFoundError(name: string, action: string): Error {\n\t\treturn new SkillNotFoundError(name, action);\n\t}\n\n\t// --- Discovery ---\n\n\tprotected override _shouldSkipFile(fileName: string): boolean {\n\t\treturn fileName === '.DS_Store';\n\t}\n\n\tprotected override _parseFrontmatter(content: string): Partial<Skill> & { _error?: string } {\n\t\tconst frontmatter = this._extractFrontmatter(content);\n\t\tif (!frontmatter) {\n\t\t\treturn {};\n\t\t}\n\n\t\ttry {\n\t\t\tconst result: Partial<Skill> = {\n\t\t\t\tname: typeof frontmatter.name === 'string' ? frontmatter.name : undefined,\n\t\t\t\tdescription: typeof frontmatter.description === 'string' ? frontmatter.description : '',\n\t\t\t\tuser_invocable: frontmatter['user-invocable'] === true,\n\t\t\t\tallowed_tools: Array.isArray(frontmatter['allowed-tools'])\n\t\t\t\t\t? frontmatter['allowed-tools'].map(String)\n\t\t\t\t\t: undefined,\n\t\t\t};\n\n\t\t\tif (!result.name) {\n\t\t\t\treturn { _error: 'Missing required field: name' };\n\t\t\t}\n\n\t\t\treturn result;\n\t\t} catch (error) {\n\t\t\tthis.log('Error parsing YAML frontmatter:', {\n\t\t\t\terror: error instanceof Error ? error.message : String(error),\n\t\t\t});\n\t\t\treturn { _error: 'YAML parse error' };\n\t\t}\n\t}\n\n\tprotected override _buildItem(parsed: Partial<Skill>): Skill | null {\n\t\tif (!parsed.name) {\n\t\t\treturn null;\n\t\t}\n\t\treturn {\n\t\t\tname: parsed.name,\n\t\t\tdescription: parsed.description || '',\n\t\t\tuser_invocable: parsed.user_invocable ?? false,\n\t\t\tallowed_tools: parsed.allowed_tools,\n\t\t};\n\t}\n}\n"],"names":["SkillRegistry","BaseRegistry","options","join","homedir","reason","InvalidSkillError","name","DuplicateSkillError","action","SkillNotFoundError","fileName","content","frontmatter","result","undefined","Array","String","error","Error","parsed"],"mappings":";;;;AAwDO,MAAMA,sBAAsBC;IACN,kBAAkB;QAAC;QAAO;QAAQ;KAAQ,CAAC;IAC3C,cAAc,QAAQ;IAElD,YAAYC,UAAgC,CAAC,CAAC,CAAE;QAC/C,KAAK,CAAC;YACL,QAAQA,QAAQ,MAAM;YACtB,OAAOA,QAAQ,KAAK;YACpB,YAAYA,QAAQ,SAAS,IAAI;gBAChC;gBACAC,KAAKC,WAAW;gBAChB;gBACAD,KAAKC,WAAW;aAChB;YACD,eAAeF,QAAQ,aAAa;QACrC;IACD;IAImB,oBAAoBG,MAAc,EAAS;QAC7D,OAAO,IAAIC,kBAAkBD;IAC9B;IAEmB,sBAAsBE,IAAY,EAAS;QAC7D,OAAO,IAAIC,oBAAoBD;IAChC;IAEmB,qBAAqBA,IAAY,EAAEE,MAAc,EAAS;QAC5E,OAAO,IAAIC,mBAAmBH,MAAME;IACrC;IAImB,gBAAgBE,QAAgB,EAAW;QAC7D,OAAOA,AAAa,gBAAbA;IACR;IAEmB,kBAAkBC,OAAe,EAAwC;QAC3F,MAAMC,cAAc,IAAI,CAAC,mBAAmB,CAACD;QAC7C,IAAI,CAACC,aACJ,OAAO,CAAC;QAGT,IAAI;YACH,MAAMC,SAAyB;gBAC9B,MAAM,AAA4B,YAA5B,OAAOD,YAAY,IAAI,GAAgBA,YAAY,IAAI,GAAGE;gBAChE,aAAa,AAAmC,YAAnC,OAAOF,YAAY,WAAW,GAAgBA,YAAY,WAAW,GAAG;gBACrF,gBAAgBA,AAAkC,SAAlCA,WAAW,CAAC,iBAAiB;gBAC7C,eAAeG,MAAM,OAAO,CAACH,WAAW,CAAC,gBAAgB,IACtDA,WAAW,CAAC,gBAAgB,CAAC,GAAG,CAACI,UACjCF;YACJ;YAEA,IAAI,CAACD,OAAO,IAAI,EACf,OAAO;gBAAE,QAAQ;YAA+B;YAGjD,OAAOA;QACR,EAAE,OAAOI,OAAO;YACf,IAAI,CAAC,GAAG,CAAC,mCAAmC;gBAC3C,OAAOA,iBAAiBC,QAAQD,MAAM,OAAO,GAAGD,OAAOC;YACxD;YACA,OAAO;gBAAE,QAAQ;YAAmB;QACrC;IACD;IAEmB,WAAWE,MAAsB,EAAgB;QACnE,IAAI,CAACA,OAAO,IAAI,EACf,OAAO;QAER,OAAO;YACN,MAAMA,OAAO,IAAI;YACjB,aAAaA,OAAO,WAAW,IAAI;YACnC,gBAAgBA,OAAO,cAAc,IAAI;YACzC,eAAeA,OAAO,aAAa;QACpC;IACD;AACD"}
@@ -43,8 +43,7 @@ export interface ToolRegistryOptions {
43
43
  /**
44
44
  * Registry for managing MCP tool operations.
45
45
  *
46
- * Extends `BaseRegistry<Tool>` with tool-specific frontmatter parsing
47
- * and backward-compatible aliases (`addTool`, `removeTool`, etc.).
46
+ * Extends `BaseRegistry<Tool>` with tool-specific frontmatter parsing.
48
47
  */
49
48
  export declare class ToolRegistry extends BaseRegistry<Tool> {
50
49
  protected readonly _fileExtensions: string[];
@@ -59,12 +58,5 @@ export declare class ToolRegistry extends BaseRegistry<Tool> {
59
58
  };
60
59
  protected _buildItem(parsed: Partial<Tool>): Tool | null;
61
60
  get(name: string): Tool | undefined;
62
- addTool(tool: Tool): void;
63
- removeTool(name: string): void;
64
- updateTool(name: string, updates: Partial<Tool>): void;
65
- hasTool(name: string): boolean;
66
- getTool(name: string): Tool | undefined;
67
- list(): string[];
68
- setTools(tools: Tool[]): void;
69
61
  }
70
62
  //# sourceMappingURL=ToolRegistry.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"ToolRegistry.d.ts","sourceRoot":"","sources":["../../src/registry/ToolRegistry.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG;AAIH,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,4BAA4B,CAAC;AAEjE,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,+BAA+B,CAAC;AAC5D,OAAO,KAAK,EAAE,IAAI,EAAE,MAAM,kBAAkB,CAAC;AAC7C,OAAO,EAAE,YAAY,EAAE,MAAM,mBAAmB,CAAC;AAEjD;;;;;;;;;;;;GAYG;AACH,MAAM,WAAW,mBAAmB;IACnC,uCAAuC;IACvC,MAAM,CAAC,EAAE,MAAM,CAAC;IAEhB,uCAAuC;IACvC,KAAK,CAAC,EAAE,cAAc,CAAC,IAAI,CAAC,CAAC;IAE7B;;;OAGG;IACH,QAAQ,CAAC,EAAE,MAAM,EAAE,CAAC;IAEpB;;;OAGG;IACH,aAAa,CAAC,EAAE,OAAO,CAAC;CACxB;AAED;;;;;GAKG;AACH,qBAAa,YAAa,SAAQ,YAAY,CAAC,IAAI,CAAC;IACnD,mBAA4B,eAAe,WAAgB;IAC3D,mBAA4B,WAAW,UAAU;gBAErC,OAAO,GAAE,mBAAwB;cAW1B,mBAAmB,CAAC,MAAM,EAAE,MAAM,GAAG,KAAK;cAI1C,qBAAqB,CAAC,IAAI,EAAE,MAAM,GAAG,KAAK;cAI1C,oBAAoB,CAAC,IAAI,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,GAAG,KAAK;cAMzD,eAAe,CAAC,SAAS,EAAE,MAAM,GAAG,OAAO;cAI3C,iBAAiB,CAAC,OAAO,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC,GAAG;QAAE,MAAM,CAAC,EAAE,MAAM,CAAA;KAAE;cA0BvE,UAAU,CAAC,MAAM,EAAE,OAAO,CAAC,IAAI,CAAC,GAAG,IAAI,GAAG,IAAI;IAajD,GAAG,CAAC,IAAI,EAAE,MAAM,GAAG,IAAI,GAAG,SAAS;IAY5C,OAAO,CAAC,IAAI,EAAE,IAAI,GAAG,IAAI;IAIzB,UAAU,CAAC,IAAI,EAAE,MAAM,GAAG,IAAI;IAI9B,UAAU,CAAC,IAAI,EAAE,MAAM,EAAE,OAAO,EAAE,OAAO,CAAC,IAAI,CAAC,GAAG,IAAI;IAItD,OAAO,CAAC,IAAI,EAAE,MAAM,GAAG,OAAO;IAI9B,OAAO,CAAC,IAAI,EAAE,MAAM,GAAG,IAAI,GAAG,SAAS;IAIvC,IAAI,IAAI,MAAM,EAAE;IAIhB,QAAQ,CAAC,KAAK,EAAE,IAAI,EAAE,GAAG,IAAI;CAGpC"}
1
+ {"version":3,"file":"ToolRegistry.d.ts","sourceRoot":"","sources":["../../src/registry/ToolRegistry.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG;AAIH,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,4BAA4B,CAAC;AAEjE,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,+BAA+B,CAAC;AAC5D,OAAO,KAAK,EAAE,IAAI,EAAE,MAAM,kBAAkB,CAAC;AAC7C,OAAO,EAAE,YAAY,EAAE,MAAM,mBAAmB,CAAC;AAEjD;;;;;;;;;;;;GAYG;AACH,MAAM,WAAW,mBAAmB;IACnC,uCAAuC;IACvC,MAAM,CAAC,EAAE,MAAM,CAAC;IAEhB,uCAAuC;IACvC,KAAK,CAAC,EAAE,cAAc,CAAC,IAAI,CAAC,CAAC;IAE7B;;;OAGG;IACH,QAAQ,CAAC,EAAE,MAAM,EAAE,CAAC;IAEpB;;;OAGG;IACH,aAAa,CAAC,EAAE,OAAO,CAAC;CACxB;AAED;;;;GAIG;AACH,qBAAa,YAAa,SAAQ,YAAY,CAAC,IAAI,CAAC;IACnD,mBAA4B,eAAe,WAAgB;IAC3D,mBAA4B,WAAW,UAAU;gBAErC,OAAO,GAAE,mBAAwB;cAW1B,mBAAmB,CAAC,MAAM,EAAE,MAAM,GAAG,KAAK;cAI1C,qBAAqB,CAAC,IAAI,EAAE,MAAM,GAAG,KAAK;cAI1C,oBAAoB,CAAC,IAAI,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,GAAG,KAAK;cAMzD,eAAe,CAAC,SAAS,EAAE,MAAM,GAAG,OAAO;cAI3C,iBAAiB,CAAC,OAAO,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC,GAAG;QAAE,MAAM,CAAC,EAAE,MAAM,CAAA;KAAE;cA0BvE,UAAU,CAAC,MAAM,EAAE,OAAO,CAAC,IAAI,CAAC,GAAG,IAAI,GAAG,IAAI;IAajD,GAAG,CAAC,IAAI,EAAE,MAAM,GAAG,IAAI,GAAG,SAAS;CASnD"}
@@ -69,27 +69,6 @@ class ToolRegistry extends BaseRegistry {
69
69
  }
70
70
  return this._items.get(name);
71
71
  }
72
- addTool(tool) {
73
- this.add(tool);
74
- }
75
- removeTool(name) {
76
- this.remove(name);
77
- }
78
- updateTool(name, updates) {
79
- this.update(name, updates);
80
- }
81
- hasTool(name) {
82
- return this.has(name);
83
- }
84
- getTool(name) {
85
- return this.get(name);
86
- }
87
- list() {
88
- return this.getNames();
89
- }
90
- setTools(tools) {
91
- this.setAll(tools);
92
- }
93
72
  }
94
73
  export { ToolRegistry };
95
74
 
@@ -1 +1 @@
1
- {"version":3,"file":"registry/ToolRegistry.js","sources":["../../src/registry/ToolRegistry.ts"],"sourcesContent":["/**\n * Tool registry for managing MCP tool CRUD operations.\n *\n * This module provides the `ToolRegistry` class which manages the registration,\n * retrieval, update, and removal of MCP tools. It supports optional caching\n * for improved performance, filesystem discovery, and integrates with the logging system.\n *\n * @module registry\n */\n\nimport { homedir } from 'node:os';\nimport { join } from 'node:path';\nimport type { DiscoveryCache } from '../cache/DiscoveryCache.js';\nimport { DuplicateToolError, InvalidToolError, ToolNotFoundError } from '../errors.js';\nimport type { Logger } from '../logger/StructuredLogger.js';\nimport type { Tool } from '../types/tool.js';\nimport { BaseRegistry } from './BaseRegistry.js';\n\n/**\n * Configuration options for creating a `ToolRegistry` instance.\n *\n * @example\n * ```typescript\n * const options: ToolRegistryOptions = {\n * logger: new StructuredLogger({ context: 'ToolRegistry' }),\n * cache: new DiscoveryCache({ ttl: 300000, maxSize: 100 }),\n * toolDirs: ['./custom-tools', '~/.claude/tools'],\n * lazyDiscovery: true\n * };\n * ```\n */\nexport interface ToolRegistryOptions {\n\t/** Optional logger for diagnostics. */\n\tlogger?: Logger;\n\n\t/** Optional cache for tool lookups. */\n\tcache?: DiscoveryCache<Tool>;\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 * Enable lazy discovery (discover on first access instead of startup).\n\t * @default false\n\t */\n\tlazyDiscovery?: boolean;\n}\n\n/**\n * Registry for managing MCP tool operations.\n *\n * Extends `BaseRegistry<Tool>` with tool-specific frontmatter parsing\n * and backward-compatible aliases (`addTool`, `removeTool`, etc.).\n */\nexport class ToolRegistry extends BaseRegistry<Tool> {\n\tprotected override readonly _fileExtensions = ['.tool.md'];\n\tprotected override readonly _entityName = 'tool';\n\n\tconstructor(options: ToolRegistryOptions = {}) {\n\t\tsuper({\n\t\t\tlogger: options.logger,\n\t\t\tcache: options.cache,\n\t\t\tsearchDirs: options.toolDirs ?? ['.claude/tools', join(homedir(), '.claude/tools')],\n\t\t\tlazyDiscovery: options.lazyDiscovery,\n\t\t});\n\t}\n\n\t// --- Error factories ---\n\n\tprotected override _createInvalidError(reason: string): Error {\n\t\treturn new InvalidToolError(reason);\n\t}\n\n\tprotected override _createDuplicateError(name: string): Error {\n\t\treturn new DuplicateToolError(name);\n\t}\n\n\tprotected override _createNotFoundError(name: string, action: string): Error {\n\t\treturn new ToolNotFoundError(name, action);\n\t}\n\n\t// --- Discovery ---\n\n\tprotected override _shouldSkipFile(_fileName: string): boolean {\n\t\treturn false;\n\t}\n\n\tprotected override _parseFrontmatter(content: string): Partial<Tool> & { _error?: string } {\n\t\tconst frontmatter = this._extractFrontmatter(content);\n\t\tif (!frontmatter) {\n\t\t\treturn { _error: 'No YAML frontmatter found' };\n\t\t}\n\n\t\ttry {\n\t\t\tconst result: Partial<Tool> = {\n\t\t\t\tname: typeof frontmatter.name === 'string' ? frontmatter.name : undefined,\n\t\t\t\tdescription: typeof frontmatter.description === 'string' ? frontmatter.description : '',\n\t\t\t\tinputSchema: frontmatter.inputSchema as Tool['inputSchema'],\n\t\t\t};\n\n\t\t\tif (!result.name) {\n\t\t\t\treturn { _error: 'Missing required field: name' };\n\t\t\t}\n\t\t\tif (!result.inputSchema) {\n\t\t\t\treturn { _error: 'Missing required field: inputSchema' };\n\t\t\t}\n\n\t\t\treturn result;\n\t\t} catch {\n\t\t\treturn { _error: 'YAML parse error' };\n\t\t}\n\t}\n\n\tprotected override _buildItem(parsed: Partial<Tool>): Tool | null {\n\t\tif (!parsed.name || !parsed.inputSchema) {\n\t\t\treturn null;\n\t\t}\n\t\treturn {\n\t\t\tname: parsed.name,\n\t\t\tdescription: parsed.description || '',\n\t\t\tinputSchema: parsed.inputSchema,\n\t\t};\n\t}\n\n\t// --- Tool-specific get with cache lookup ---\n\n\tpublic override get(name: string): Tool | undefined {\n\t\tif (this._cache) {\n\t\t\tconst cached = this._cache.get(`tool:${name}`);\n\t\t\tif (cached && cached.length > 0) {\n\t\t\t\treturn cached[0];\n\t\t\t}\n\t\t}\n\t\treturn this._items.get(name);\n\t}\n\n\t// --- Backward-compatible aliases ---\n\n\tpublic addTool(tool: Tool): void {\n\t\tthis.add(tool);\n\t}\n\n\tpublic removeTool(name: string): void {\n\t\tthis.remove(name);\n\t}\n\n\tpublic updateTool(name: string, updates: Partial<Tool>): void {\n\t\tthis.update(name, updates);\n\t}\n\n\tpublic hasTool(name: string): boolean {\n\t\treturn this.has(name);\n\t}\n\n\tpublic getTool(name: string): Tool | undefined {\n\t\treturn this.get(name);\n\t}\n\n\tpublic list(): string[] {\n\t\treturn this.getNames();\n\t}\n\n\tpublic setTools(tools: Tool[]): void {\n\t\tthis.setAll(tools);\n\t}\n}\n"],"names":["ToolRegistry","BaseRegistry","options","join","homedir","reason","InvalidToolError","name","DuplicateToolError","action","ToolNotFoundError","_fileName","content","frontmatter","result","undefined","parsed","cached","tool","updates","tools"],"mappings":";;;;AAyDO,MAAMA,qBAAqBC;IACL,kBAAkB;QAAC;KAAW,CAAC;IAC/B,cAAc,OAAO;IAEjD,YAAYC,UAA+B,CAAC,CAAC,CAAE;QAC9C,KAAK,CAAC;YACL,QAAQA,QAAQ,MAAM;YACtB,OAAOA,QAAQ,KAAK;YACpB,YAAYA,QAAQ,QAAQ,IAAI;gBAAC;gBAAiBC,KAAKC,WAAW;aAAiB;YACnF,eAAeF,QAAQ,aAAa;QACrC;IACD;IAImB,oBAAoBG,MAAc,EAAS;QAC7D,OAAO,IAAIC,iBAAiBD;IAC7B;IAEmB,sBAAsBE,IAAY,EAAS;QAC7D,OAAO,IAAIC,mBAAmBD;IAC/B;IAEmB,qBAAqBA,IAAY,EAAEE,MAAc,EAAS;QAC5E,OAAO,IAAIC,kBAAkBH,MAAME;IACpC;IAImB,gBAAgBE,SAAiB,EAAW;QAC9D,OAAO;IACR;IAEmB,kBAAkBC,OAAe,EAAuC;QAC1F,MAAMC,cAAc,IAAI,CAAC,mBAAmB,CAACD;QAC7C,IAAI,CAACC,aACJ,OAAO;YAAE,QAAQ;QAA4B;QAG9C,IAAI;YACH,MAAMC,SAAwB;gBAC7B,MAAM,AAA4B,YAA5B,OAAOD,YAAY,IAAI,GAAgBA,YAAY,IAAI,GAAGE;gBAChE,aAAa,AAAmC,YAAnC,OAAOF,YAAY,WAAW,GAAgBA,YAAY,WAAW,GAAG;gBACrF,aAAaA,YAAY,WAAW;YACrC;YAEA,IAAI,CAACC,OAAO,IAAI,EACf,OAAO;gBAAE,QAAQ;YAA+B;YAEjD,IAAI,CAACA,OAAO,WAAW,EACtB,OAAO;gBAAE,QAAQ;YAAsC;YAGxD,OAAOA;QACR,EAAE,OAAM;YACP,OAAO;gBAAE,QAAQ;YAAmB;QACrC;IACD;IAEmB,WAAWE,MAAqB,EAAe;QACjE,IAAI,CAACA,OAAO,IAAI,IAAI,CAACA,OAAO,WAAW,EACtC,OAAO;QAER,OAAO;YACN,MAAMA,OAAO,IAAI;YACjB,aAAaA,OAAO,WAAW,IAAI;YACnC,aAAaA,OAAO,WAAW;QAChC;IACD;IAIgB,IAAIT,IAAY,EAAoB;QACnD,IAAI,IAAI,CAAC,MAAM,EAAE;YAChB,MAAMU,SAAS,IAAI,CAAC,MAAM,CAAC,GAAG,CAAC,CAAC,KAAK,EAAEV,MAAM;YAC7C,IAAIU,UAAUA,OAAO,MAAM,GAAG,GAC7B,OAAOA,MAAM,CAAC,EAAE;QAElB;QACA,OAAO,IAAI,CAAC,MAAM,CAAC,GAAG,CAACV;IACxB;IAIO,QAAQW,IAAU,EAAQ;QAChC,IAAI,CAAC,GAAG,CAACA;IACV;IAEO,WAAWX,IAAY,EAAQ;QACrC,IAAI,CAAC,MAAM,CAACA;IACb;IAEO,WAAWA,IAAY,EAAEY,OAAsB,EAAQ;QAC7D,IAAI,CAAC,MAAM,CAACZ,MAAMY;IACnB;IAEO,QAAQZ,IAAY,EAAW;QACrC,OAAO,IAAI,CAAC,GAAG,CAACA;IACjB;IAEO,QAAQA,IAAY,EAAoB;QAC9C,OAAO,IAAI,CAAC,GAAG,CAACA;IACjB;IAEO,OAAiB;QACvB,OAAO,IAAI,CAAC,QAAQ;IACrB;IAEO,SAASa,KAAa,EAAQ;QACpC,IAAI,CAAC,MAAM,CAACA;IACb;AACD"}
1
+ {"version":3,"file":"registry/ToolRegistry.js","sources":["../../src/registry/ToolRegistry.ts"],"sourcesContent":["/**\n * Tool registry for managing MCP tool CRUD operations.\n *\n * This module provides the `ToolRegistry` class which manages the registration,\n * retrieval, update, and removal of MCP tools. It supports optional caching\n * for improved performance, filesystem discovery, and integrates with the logging system.\n *\n * @module registry\n */\n\nimport { homedir } from 'node:os';\nimport { join } from 'node:path';\nimport type { DiscoveryCache } from '../cache/DiscoveryCache.js';\nimport { DuplicateToolError, InvalidToolError, ToolNotFoundError } from '../errors.js';\nimport type { Logger } from '../logger/StructuredLogger.js';\nimport type { Tool } from '../types/tool.js';\nimport { BaseRegistry } from './BaseRegistry.js';\n\n/**\n * Configuration options for creating a `ToolRegistry` instance.\n *\n * @example\n * ```typescript\n * const options: ToolRegistryOptions = {\n * logger: new StructuredLogger({ context: 'ToolRegistry' }),\n * cache: new DiscoveryCache({ ttl: 300000, maxSize: 100 }),\n * toolDirs: ['./custom-tools', '~/.claude/tools'],\n * lazyDiscovery: true\n * };\n * ```\n */\nexport interface ToolRegistryOptions {\n\t/** Optional logger for diagnostics. */\n\tlogger?: Logger;\n\n\t/** Optional cache for tool lookups. */\n\tcache?: DiscoveryCache<Tool>;\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 * Enable lazy discovery (discover on first access instead of startup).\n\t * @default false\n\t */\n\tlazyDiscovery?: boolean;\n}\n\n/**\n * Registry for managing MCP tool operations.\n *\n * Extends `BaseRegistry<Tool>` with tool-specific frontmatter parsing.\n */\nexport class ToolRegistry extends BaseRegistry<Tool> {\n\tprotected override readonly _fileExtensions = ['.tool.md'];\n\tprotected override readonly _entityName = 'tool';\n\n\tconstructor(options: ToolRegistryOptions = {}) {\n\t\tsuper({\n\t\t\tlogger: options.logger,\n\t\t\tcache: options.cache,\n\t\t\tsearchDirs: options.toolDirs ?? ['.claude/tools', join(homedir(), '.claude/tools')],\n\t\t\tlazyDiscovery: options.lazyDiscovery,\n\t\t});\n\t}\n\n\t// --- Error factories ---\n\n\tprotected override _createInvalidError(reason: string): Error {\n\t\treturn new InvalidToolError(reason);\n\t}\n\n\tprotected override _createDuplicateError(name: string): Error {\n\t\treturn new DuplicateToolError(name);\n\t}\n\n\tprotected override _createNotFoundError(name: string, action: string): Error {\n\t\treturn new ToolNotFoundError(name, action);\n\t}\n\n\t// --- Discovery ---\n\n\tprotected override _shouldSkipFile(_fileName: string): boolean {\n\t\treturn false;\n\t}\n\n\tprotected override _parseFrontmatter(content: string): Partial<Tool> & { _error?: string } {\n\t\tconst frontmatter = this._extractFrontmatter(content);\n\t\tif (!frontmatter) {\n\t\t\treturn { _error: 'No YAML frontmatter found' };\n\t\t}\n\n\t\ttry {\n\t\t\tconst result: Partial<Tool> = {\n\t\t\t\tname: typeof frontmatter.name === 'string' ? frontmatter.name : undefined,\n\t\t\t\tdescription: typeof frontmatter.description === 'string' ? frontmatter.description : '',\n\t\t\t\tinputSchema: frontmatter.inputSchema as Tool['inputSchema'],\n\t\t\t};\n\n\t\t\tif (!result.name) {\n\t\t\t\treturn { _error: 'Missing required field: name' };\n\t\t\t}\n\t\t\tif (!result.inputSchema) {\n\t\t\t\treturn { _error: 'Missing required field: inputSchema' };\n\t\t\t}\n\n\t\t\treturn result;\n\t\t} catch {\n\t\t\treturn { _error: 'YAML parse error' };\n\t\t}\n\t}\n\n\tprotected override _buildItem(parsed: Partial<Tool>): Tool | null {\n\t\tif (!parsed.name || !parsed.inputSchema) {\n\t\t\treturn null;\n\t\t}\n\t\treturn {\n\t\t\tname: parsed.name,\n\t\t\tdescription: parsed.description || '',\n\t\t\tinputSchema: parsed.inputSchema,\n\t\t};\n\t}\n\n\t// --- Tool-specific get with cache lookup ---\n\n\tpublic override get(name: string): Tool | undefined {\n\t\tif (this._cache) {\n\t\t\tconst cached = this._cache.get(`tool:${name}`);\n\t\t\tif (cached && cached.length > 0) {\n\t\t\t\treturn cached[0];\n\t\t\t}\n\t\t}\n\t\treturn this._items.get(name);\n\t}\n}\n"],"names":["ToolRegistry","BaseRegistry","options","join","homedir","reason","InvalidToolError","name","DuplicateToolError","action","ToolNotFoundError","_fileName","content","frontmatter","result","undefined","parsed","cached"],"mappings":";;;;AAwDO,MAAMA,qBAAqBC;IACL,kBAAkB;QAAC;KAAW,CAAC;IAC/B,cAAc,OAAO;IAEjD,YAAYC,UAA+B,CAAC,CAAC,CAAE;QAC9C,KAAK,CAAC;YACL,QAAQA,QAAQ,MAAM;YACtB,OAAOA,QAAQ,KAAK;YACpB,YAAYA,QAAQ,QAAQ,IAAI;gBAAC;gBAAiBC,KAAKC,WAAW;aAAiB;YACnF,eAAeF,QAAQ,aAAa;QACrC;IACD;IAImB,oBAAoBG,MAAc,EAAS;QAC7D,OAAO,IAAIC,iBAAiBD;IAC7B;IAEmB,sBAAsBE,IAAY,EAAS;QAC7D,OAAO,IAAIC,mBAAmBD;IAC/B;IAEmB,qBAAqBA,IAAY,EAAEE,MAAc,EAAS;QAC5E,OAAO,IAAIC,kBAAkBH,MAAME;IACpC;IAImB,gBAAgBE,SAAiB,EAAW;QAC9D,OAAO;IACR;IAEmB,kBAAkBC,OAAe,EAAuC;QAC1F,MAAMC,cAAc,IAAI,CAAC,mBAAmB,CAACD;QAC7C,IAAI,CAACC,aACJ,OAAO;YAAE,QAAQ;QAA4B;QAG9C,IAAI;YACH,MAAMC,SAAwB;gBAC7B,MAAM,AAA4B,YAA5B,OAAOD,YAAY,IAAI,GAAgBA,YAAY,IAAI,GAAGE;gBAChE,aAAa,AAAmC,YAAnC,OAAOF,YAAY,WAAW,GAAgBA,YAAY,WAAW,GAAG;gBACrF,aAAaA,YAAY,WAAW;YACrC;YAEA,IAAI,CAACC,OAAO,IAAI,EACf,OAAO;gBAAE,QAAQ;YAA+B;YAEjD,IAAI,CAACA,OAAO,WAAW,EACtB,OAAO;gBAAE,QAAQ;YAAsC;YAGxD,OAAOA;QACR,EAAE,OAAM;YACP,OAAO;gBAAE,QAAQ;YAAmB;QACrC;IACD;IAEmB,WAAWE,MAAqB,EAAe;QACjE,IAAI,CAACA,OAAO,IAAI,IAAI,CAACA,OAAO,WAAW,EACtC,OAAO;QAER,OAAO;YACN,MAAMA,OAAO,IAAI;YACjB,aAAaA,OAAO,WAAW,IAAI;YACnC,aAAaA,OAAO,WAAW;QAChC;IACD;IAIgB,IAAIT,IAAY,EAAoB;QACnD,IAAI,IAAI,CAAC,MAAM,EAAE;YAChB,MAAMU,SAAS,IAAI,CAAC,MAAM,CAAC,GAAG,CAAC,CAAC,KAAK,EAAEV,MAAM;YAC7C,IAAIU,UAAUA,OAAO,MAAM,GAAG,GAC7B,OAAOA,MAAM,CAAC,EAAE;QAElB;QACA,OAAO,IAAI,CAAC,MAAM,CAAC,GAAG,CAACV;IACxB;AACD"}
package/dist/schema.d.ts CHANGED
@@ -315,6 +315,7 @@ export declare const PartialStepRecommendationSchema: v.ObjectSchema<{
315
315
  * thought: 'I need to analyze the problem',
316
316
  * thought_number: 1,
317
317
  * total_thoughts: 5,
318
+ * session_id: 'analysis-task',
318
319
  * next_thought_needed: true,
319
320
  * available_mcp_tools: ['Read', 'Write', 'Grep']
320
321
  * });
@@ -479,7 +480,7 @@ export declare const SequentialThinkingSchema: v.ObjectSchema<{
479
480
  readonly merge_branch_ids: v.OptionalSchema<v.SchemaWithPipe<readonly [v.ArraySchema<v.SchemaWithPipe<readonly [v.StringSchema<undefined>, v.RegexAction<string, undefined>, v.MaxLengthAction<string, 50, undefined>]>, undefined>, v.DescriptionAction<string[], "Branch IDs being merged into current context">]>, undefined>;
480
481
  readonly meta_observation: v.OptionalSchema<v.SchemaWithPipe<readonly [v.StringSchema<undefined>, v.DescriptionAction<string, "Metacognitive observation about reasoning process">]>, undefined>;
481
482
  readonly reasoning_depth: v.OptionalSchema<v.SchemaWithPipe<readonly [v.PicklistSchema<["shallow", "moderate", "deep"], undefined>, v.DescriptionAction<"shallow" | "moderate" | "deep", "Effort signal: how deep reasoning should go">]>, undefined>;
482
- readonly session_id: v.OptionalSchema<v.SchemaWithPipe<readonly [v.StringSchema<undefined>, v.RegexAction<string, "Session ID must contain only letters, numbers, hyphens, and underscores">, v.MinLengthAction<string, 1, undefined>, v.MaxLengthAction<string, 100, undefined>, v.DescriptionAction<string, "Optional session identifier for state isolation. When provided, thought history, branches, and statistics are scoped to this session. Omitting preserves global behavior.">]>, undefined>;
483
+ readonly session_id: v.SchemaWithPipe<readonly [v.StringSchema<undefined>, v.RegexAction<string, "Session ID must contain only letters, numbers, hyphens, and underscores">, v.MinLengthAction<string, 1, undefined>, v.MaxLengthAction<string, 100, undefined>, v.NotValueAction<string, "__global__", "Session ID '__global__' is retired; use an explicit named session">, v.DescriptionAction<string, "Required session identifier for state isolation. Thought history, branches, and statistics are scoped to this explicit named session.">]>;
483
484
  readonly reset_state: v.OptionalSchema<v.SchemaWithPipe<readonly [v.BooleanSchema<undefined>, v.DescriptionAction<boolean, "When true, clears all state for the target session before processing this thought. The thought is then processed as the first in a fresh session.">]>, undefined>;
484
485
  readonly tool_name: v.OptionalSchema<v.SchemaWithPipe<readonly [v.StringSchema<undefined>, v.MinLengthAction<string, 1, undefined>, v.DescriptionAction<string, "Name of the tool being invoked (for tool_call thoughts)">]>, undefined>;
485
486
  readonly tool_arguments: v.OptionalSchema<v.SchemaWithPipe<readonly [v.RecordSchema<v.StringSchema<undefined>, v.UnknownSchema, undefined>, v.DescriptionAction<{