@easynet/agent-tool-hub 1.0.6

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (42) hide show
  1. package/README.md +132 -0
  2. package/dist/N8nLocalAdapter-6RKQJXJP.js +4 -0
  3. package/dist/N8nLocalAdapter-6RKQJXJP.js.map +1 -0
  4. package/dist/N8nLocalAdapter-MDWME5ZG.cjs +13 -0
  5. package/dist/N8nLocalAdapter-MDWME5ZG.cjs.map +1 -0
  6. package/dist/chunk-57LVNNHL.js +19 -0
  7. package/dist/chunk-57LVNNHL.js.map +1 -0
  8. package/dist/chunk-6QTWECRD.cjs +23 -0
  9. package/dist/chunk-6QTWECRD.cjs.map +1 -0
  10. package/dist/chunk-HPDQEW2P.js +5251 -0
  11. package/dist/chunk-HPDQEW2P.js.map +1 -0
  12. package/dist/chunk-MHEFFZBB.js +134 -0
  13. package/dist/chunk-MHEFFZBB.js.map +1 -0
  14. package/dist/chunk-NTTBDQUF.cjs +118 -0
  15. package/dist/chunk-NTTBDQUF.cjs.map +1 -0
  16. package/dist/chunk-TIKHPRMB.cjs +5313 -0
  17. package/dist/chunk-TIKHPRMB.cjs.map +1 -0
  18. package/dist/chunk-X53WXBKX.cjs +136 -0
  19. package/dist/chunk-X53WXBKX.cjs.map +1 -0
  20. package/dist/chunk-YSYEED4K.js +114 -0
  21. package/dist/chunk-YSYEED4K.js.map +1 -0
  22. package/dist/cli.cjs +194 -0
  23. package/dist/cli.cjs.map +1 -0
  24. package/dist/cli.d.cts +10 -0
  25. package/dist/cli.d.ts +10 -0
  26. package/dist/cli.js +186 -0
  27. package/dist/cli.js.map +1 -0
  28. package/dist/index.cjs +592 -0
  29. package/dist/index.cjs.map +1 -0
  30. package/dist/index.d.cts +552 -0
  31. package/dist/index.d.ts +552 -0
  32. package/dist/index.js +358 -0
  33. package/dist/index.js.map +1 -0
  34. package/dist/toolhub-runtime-CQkP4QVW.d.cts +1564 -0
  35. package/dist/toolhub-runtime-CQkP4QVW.d.ts +1564 -0
  36. package/dist/toolhub-runtime.cjs +30 -0
  37. package/dist/toolhub-runtime.cjs.map +1 -0
  38. package/dist/toolhub-runtime.d.cts +4 -0
  39. package/dist/toolhub-runtime.d.ts +4 -0
  40. package/dist/toolhub-runtime.js +5 -0
  41. package/dist/toolhub-runtime.js.map +1 -0
  42. package/package.json +77 -0
package/dist/index.js ADDED
@@ -0,0 +1,358 @@
1
+ export { createAgentToolHub, createToolHubAndInitFromConfig } from './chunk-57LVNNHL.js';
2
+ import { DirectoryScanner } from './chunk-HPDQEW2P.js';
3
+ export { BudgetManager, ComfyUIAdapter, CoreAdapter, DEFAULT_CORE_TOOLS_CONFIG, DirectoryScanner, DiscoveryError, EventLog, LangChainAdapter, MCPAdapter, Metrics, N8nAdapter, PTCRuntime, PolicyDeniedError, PolicyEngine, SchemaValidationError, SchemaValidator, SkillAdapter, SkillManifestError, ToolHub, ToolRegistry, Tracing, buildEvidence, createTaggedError, createToolHub, deletePathSpec, downloadFileSpec, fetchJsonSpec, fetchTextSpec, hashTextSpec, headSpec, isIpInBlockedCidrs, isRetryable, jsonSelectSpec, listDirSpec, loadSkillDefinition, loadToolHubConfig, mapToolHubConfig, nowSpec, parseSkillMd, readTextSpec, registerCoreTools, resolveSandboxedPath, scanSkillResources, searchTextSpec, sha256Spec, templateRenderSpec, truncateSpec, validateFrontmatter, validateUrl, withRetry, writeTextSpec } from './chunk-HPDQEW2P.js';
4
+ export { N8nLocalAdapter } from './chunk-MHEFFZBB.js';
5
+ export { createLogger, sanitizeForLog, summarizeForLog } from './chunk-YSYEED4K.js';
6
+ import { v4 } from 'uuid';
7
+ import { EventEmitter } from 'eventemitter3';
8
+
9
+ // src/registry/Discovery.ts
10
+ var Discovery = class {
11
+ sources = /* @__PURE__ */ new Map();
12
+ timers = /* @__PURE__ */ new Map();
13
+ registry;
14
+ lastRefresh = /* @__PURE__ */ new Map();
15
+ discoveredTools = /* @__PURE__ */ new Map();
16
+ // sourceId → tool names
17
+ constructor(registry) {
18
+ this.registry = registry;
19
+ }
20
+ /**
21
+ * Add a discovery source.
22
+ */
23
+ addSource(source) {
24
+ this.sources.set(source.id, source);
25
+ this.discoveredTools.set(source.id, /* @__PURE__ */ new Set());
26
+ if (source.refreshIntervalMs && source.refreshIntervalMs > 0) {
27
+ const timer = setInterval(
28
+ () => void this.refresh(source.id),
29
+ source.refreshIntervalMs
30
+ );
31
+ if (typeof timer === "object" && "unref" in timer) {
32
+ timer.unref();
33
+ }
34
+ this.timers.set(source.id, timer);
35
+ }
36
+ if (source.autoDiscover) {
37
+ void this.refresh(source.id);
38
+ }
39
+ }
40
+ /**
41
+ * Remove a discovery source and its registered tools.
42
+ */
43
+ removeSource(id) {
44
+ const timer = this.timers.get(id);
45
+ if (timer) {
46
+ clearInterval(timer);
47
+ this.timers.delete(id);
48
+ }
49
+ const tools = this.discoveredTools.get(id);
50
+ if (tools) {
51
+ for (const name of tools) {
52
+ this.registry.unregister(name);
53
+ }
54
+ }
55
+ this.sources.delete(id);
56
+ this.discoveredTools.delete(id);
57
+ this.lastRefresh.delete(id);
58
+ }
59
+ /**
60
+ * Refresh tools from a specific source (or all sources).
61
+ */
62
+ async refresh(sourceId) {
63
+ if (sourceId) {
64
+ return this.refreshSource(sourceId);
65
+ }
66
+ const allSpecs = [];
67
+ for (const id of this.sources.keys()) {
68
+ const specs = await this.refreshSource(id);
69
+ allSpecs.push(...specs);
70
+ }
71
+ return allSpecs;
72
+ }
73
+ /**
74
+ * Get the last refresh timestamp for a source.
75
+ */
76
+ getLastRefresh(sourceId) {
77
+ return this.lastRefresh.get(sourceId);
78
+ }
79
+ /**
80
+ * Get all registered source IDs.
81
+ */
82
+ getSources() {
83
+ return [...this.sources.keys()];
84
+ }
85
+ /**
86
+ * Stop all refresh timers.
87
+ */
88
+ dispose() {
89
+ for (const timer of this.timers.values()) {
90
+ clearInterval(timer);
91
+ }
92
+ this.timers.clear();
93
+ }
94
+ async refreshSource(sourceId) {
95
+ const source = this.sources.get(sourceId);
96
+ if (!source) return [];
97
+ if (!source.adapter.listTools) {
98
+ return [];
99
+ }
100
+ try {
101
+ const specs = await source.adapter.listTools();
102
+ const currentTools = this.discoveredTools.get(sourceId) ?? /* @__PURE__ */ new Set();
103
+ const newToolNames = new Set(specs.map((s) => s.name));
104
+ for (const name of currentTools) {
105
+ if (!newToolNames.has(name)) {
106
+ this.registry.unregister(name);
107
+ }
108
+ }
109
+ for (const spec of specs) {
110
+ this.registry.register(spec);
111
+ }
112
+ this.discoveredTools.set(sourceId, newToolNames);
113
+ this.lastRefresh.set(sourceId, Date.now());
114
+ return specs;
115
+ } catch (error) {
116
+ console.error(`Discovery refresh failed for source ${sourceId}:`, error);
117
+ return [];
118
+ }
119
+ }
120
+ };
121
+ var InMemoryJobStore = class {
122
+ jobs = /* @__PURE__ */ new Map();
123
+ async set(jobId, job) {
124
+ this.jobs.set(jobId, job);
125
+ }
126
+ async get(jobId) {
127
+ return this.jobs.get(jobId);
128
+ }
129
+ async list(filter) {
130
+ let results = [...this.jobs.values()];
131
+ if (filter?.toolName) {
132
+ results = results.filter((j) => j.toolName === filter.toolName);
133
+ }
134
+ if (filter?.status) {
135
+ results = results.filter((j) => j.status === filter.status);
136
+ }
137
+ return results;
138
+ }
139
+ async delete(jobId) {
140
+ this.jobs.delete(jobId);
141
+ }
142
+ get size() {
143
+ return this.jobs.size;
144
+ }
145
+ clear() {
146
+ this.jobs.clear();
147
+ }
148
+ };
149
+ var AsyncJobManager = class {
150
+ store;
151
+ emitter = new EventEmitter();
152
+ ttlMs;
153
+ cleanupTimer;
154
+ constructor(options = {}) {
155
+ this.store = options.store ?? new InMemoryJobStore();
156
+ this.ttlMs = options.ttlMs ?? 36e5;
157
+ this.startCleanup();
158
+ }
159
+ /**
160
+ * Submit a new async job.
161
+ */
162
+ async submit(options) {
163
+ const now = Date.now();
164
+ const job = {
165
+ jobId: v4(),
166
+ toolName: options.toolName,
167
+ requestId: options.requestId,
168
+ taskId: options.taskId,
169
+ status: "queued",
170
+ createdAt: now,
171
+ updatedAt: now,
172
+ metadata: options.metadata
173
+ };
174
+ await this.store.set(job.jobId, job);
175
+ this.emitter.emit("submitted", job);
176
+ return job;
177
+ }
178
+ /**
179
+ * Update job status to running.
180
+ */
181
+ async markRunning(jobId) {
182
+ const job = await this.store.get(jobId);
183
+ if (!job) return void 0;
184
+ job.status = "running";
185
+ job.updatedAt = Date.now();
186
+ await this.store.set(jobId, job);
187
+ this.emitter.emit("running", job);
188
+ return job;
189
+ }
190
+ /**
191
+ * Complete a job with a result.
192
+ */
193
+ async complete(jobId, result) {
194
+ const job = await this.store.get(jobId);
195
+ if (!job) return void 0;
196
+ job.status = "completed";
197
+ job.result = result;
198
+ job.updatedAt = Date.now();
199
+ await this.store.set(jobId, job);
200
+ this.emitter.emit("completed", job);
201
+ return job;
202
+ }
203
+ /**
204
+ * Fail a job with an error message.
205
+ */
206
+ async fail(jobId, error) {
207
+ const job = await this.store.get(jobId);
208
+ if (!job) return void 0;
209
+ job.status = "failed";
210
+ job.error = error;
211
+ job.updatedAt = Date.now();
212
+ await this.store.set(jobId, job);
213
+ this.emitter.emit("failed", job);
214
+ return job;
215
+ }
216
+ /**
217
+ * Get current job status.
218
+ */
219
+ async getStatus(jobId) {
220
+ const job = await this.store.get(jobId);
221
+ return job?.status;
222
+ }
223
+ /**
224
+ * Get the full job record.
225
+ */
226
+ async getJob(jobId) {
227
+ return this.store.get(jobId);
228
+ }
229
+ /**
230
+ * Get the result of a completed job.
231
+ */
232
+ async getResult(jobId) {
233
+ const job = await this.store.get(jobId);
234
+ if (!job || job.status !== "completed") return void 0;
235
+ return job.result;
236
+ }
237
+ /**
238
+ * List jobs with optional filter.
239
+ */
240
+ async list(filter) {
241
+ return this.store.list(filter);
242
+ }
243
+ /**
244
+ * Subscribe to job events.
245
+ */
246
+ on(event, listener) {
247
+ this.emitter.on(event, listener);
248
+ return () => this.emitter.off(event, listener);
249
+ }
250
+ /**
251
+ * Stop cleanup timer.
252
+ */
253
+ dispose() {
254
+ if (this.cleanupTimer) {
255
+ clearInterval(this.cleanupTimer);
256
+ this.cleanupTimer = void 0;
257
+ }
258
+ }
259
+ startCleanup() {
260
+ const interval = Math.max(this.ttlMs / 2, 6e4);
261
+ this.cleanupTimer = setInterval(() => void this.cleanup(), interval);
262
+ if (typeof this.cleanupTimer === "object" && "unref" in this.cleanupTimer) {
263
+ this.cleanupTimer.unref();
264
+ }
265
+ }
266
+ async cleanup() {
267
+ const now = Date.now();
268
+ const all = await this.store.list();
269
+ for (const job of all) {
270
+ if ((job.status === "completed" || job.status === "failed") && now - job.updatedAt > this.ttlMs) {
271
+ await this.store.delete(job.jobId);
272
+ }
273
+ }
274
+ }
275
+ };
276
+
277
+ // src/discovery/DirectoryDiscoverySource.ts
278
+ var DirectoryToolAdapter = class {
279
+ kind = "mcp";
280
+ // Required by ToolAdapter but not used for routing
281
+ scanner;
282
+ constructor(options) {
283
+ this.scanner = new DirectoryScanner(options);
284
+ }
285
+ /**
286
+ * Scan directories and return discovered tool specs.
287
+ * Called by Discovery.refresh().
288
+ */
289
+ async listTools() {
290
+ return this.scanner.scan();
291
+ }
292
+ /**
293
+ * Not used — actual invocation routes through kind-specific adapters.
294
+ */
295
+ async invoke(_spec, _args, _ctx) {
296
+ throw new Error(
297
+ "DirectoryToolAdapter.invoke() should not be called directly. Tool execution is handled by the kind-specific adapter (MCPAdapter, LangChainAdapter, etc.)."
298
+ );
299
+ }
300
+ /**
301
+ * Get the underlying scanner for direct usage.
302
+ */
303
+ getScanner() {
304
+ return this.scanner;
305
+ }
306
+ };
307
+ function createDirectoryDiscoverySource(id, options) {
308
+ const { refreshIntervalMs, autoDiscover, ...scannerOptions } = options;
309
+ return {
310
+ id,
311
+ adapter: new DirectoryToolAdapter(scannerOptions),
312
+ refreshIntervalMs: refreshIntervalMs ?? 0,
313
+ autoDiscover: autoDiscover ?? true
314
+ };
315
+ }
316
+
317
+ // src/discovery/MCPProcessManager.ts
318
+ var MCPProcessManager = class {
319
+ connections = /* @__PURE__ */ new Map();
320
+ /**
321
+ * Get connection info for an MCP tool based on its config.
322
+ * Caches the result by tool name.
323
+ */
324
+ getConnectionInfo(toolName, config) {
325
+ const cached = this.connections.get(toolName);
326
+ if (cached) return cached;
327
+ const info = config.url ? { type: "url", url: config.url } : {
328
+ type: "stdio",
329
+ command: config.command,
330
+ args: config.args,
331
+ env: config.env
332
+ };
333
+ this.connections.set(toolName, info);
334
+ return info;
335
+ }
336
+ /**
337
+ * Remove cached connection info for a tool.
338
+ */
339
+ remove(toolName) {
340
+ return this.connections.delete(toolName);
341
+ }
342
+ /**
343
+ * Get all registered tool names.
344
+ */
345
+ getToolNames() {
346
+ return [...this.connections.keys()];
347
+ }
348
+ /**
349
+ * Clear all cached connection info.
350
+ */
351
+ dispose() {
352
+ this.connections.clear();
353
+ }
354
+ };
355
+
356
+ export { AsyncJobManager, DirectoryToolAdapter, Discovery, InMemoryJobStore, MCPProcessManager, createDirectoryDiscoverySource };
357
+ //# sourceMappingURL=index.js.map
358
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/registry/Discovery.ts","../src/jobs/AsyncJobManager.ts","../src/discovery/DirectoryDiscoverySource.ts","../src/discovery/MCPProcessManager.ts"],"names":["uuidv4"],"mappings":"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","file":"index.js","sourcesContent":["import type { ToolAdapter, ToolSpec } from \"../types/ToolSpec.js\";\nimport type { ToolRegistry } from \"./ToolRegistry.js\";\n\n/**\n * Discovery source configuration.\n */\nexport interface DiscoverySource {\n /** Unique identifier for this source */\n id: string;\n /** The adapter that supports listTools() */\n adapter: ToolAdapter;\n /** Refresh interval in ms (0 = manual only) */\n refreshIntervalMs?: number;\n /** Whether to auto-discover on startup */\n autoDiscover?: boolean;\n}\n\n/**\n * Discovery manager that pulls tool specs from adapters\n * and registers them into the ToolRegistry.\n */\nexport class Discovery {\n private readonly sources = new Map<string, DiscoverySource>();\n private readonly timers = new Map<string, ReturnType<typeof setInterval>>();\n private readonly registry: ToolRegistry;\n private readonly lastRefresh = new Map<string, number>();\n private readonly discoveredTools = new Map<string, Set<string>>(); // sourceId → tool names\n\n constructor(registry: ToolRegistry) {\n this.registry = registry;\n }\n\n /**\n * Add a discovery source.\n */\n addSource(source: DiscoverySource): void {\n this.sources.set(source.id, source);\n this.discoveredTools.set(source.id, new Set());\n\n // Start auto-refresh if configured\n if (source.refreshIntervalMs && source.refreshIntervalMs > 0) {\n const timer = setInterval(\n () => void this.refresh(source.id),\n source.refreshIntervalMs,\n );\n // Unref so it doesn't prevent process exit\n if (typeof timer === \"object\" && \"unref\" in timer) {\n timer.unref();\n }\n this.timers.set(source.id, timer);\n }\n\n // Auto-discover on add if configured\n if (source.autoDiscover) {\n void this.refresh(source.id);\n }\n }\n\n /**\n * Remove a discovery source and its registered tools.\n */\n removeSource(id: string): void {\n const timer = this.timers.get(id);\n if (timer) {\n clearInterval(timer);\n this.timers.delete(id);\n }\n\n // Unregister tools from this source\n const tools = this.discoveredTools.get(id);\n if (tools) {\n for (const name of tools) {\n this.registry.unregister(name);\n }\n }\n\n this.sources.delete(id);\n this.discoveredTools.delete(id);\n this.lastRefresh.delete(id);\n }\n\n /**\n * Refresh tools from a specific source (or all sources).\n */\n async refresh(sourceId?: string): Promise<ToolSpec[]> {\n if (sourceId) {\n return this.refreshSource(sourceId);\n }\n\n const allSpecs: ToolSpec[] = [];\n for (const id of this.sources.keys()) {\n const specs = await this.refreshSource(id);\n allSpecs.push(...specs);\n }\n return allSpecs;\n }\n\n /**\n * Get the last refresh timestamp for a source.\n */\n getLastRefresh(sourceId: string): number | undefined {\n return this.lastRefresh.get(sourceId);\n }\n\n /**\n * Get all registered source IDs.\n */\n getSources(): string[] {\n return [...this.sources.keys()];\n }\n\n /**\n * Stop all refresh timers.\n */\n dispose(): void {\n for (const timer of this.timers.values()) {\n clearInterval(timer);\n }\n this.timers.clear();\n }\n\n private async refreshSource(sourceId: string): Promise<ToolSpec[]> {\n const source = this.sources.get(sourceId);\n if (!source) return [];\n\n if (!source.adapter.listTools) {\n return [];\n }\n\n try {\n const specs = await source.adapter.listTools();\n const currentTools = this.discoveredTools.get(sourceId) ?? new Set();\n const newToolNames = new Set(specs.map((s) => s.name));\n\n // Unregister tools that are no longer present\n for (const name of currentTools) {\n if (!newToolNames.has(name)) {\n this.registry.unregister(name);\n }\n }\n\n // Register/update tools\n for (const spec of specs) {\n this.registry.register(spec);\n }\n\n this.discoveredTools.set(sourceId, newToolNames);\n this.lastRefresh.set(sourceId, Date.now());\n\n return specs;\n } catch (error) {\n // Log but don't throw - discovery failures shouldn't crash the system\n console.error(`Discovery refresh failed for source ${sourceId}:`, error);\n return [];\n }\n }\n}\n","import { v4 as uuidv4 } from \"uuid\";\nimport { EventEmitter } from \"eventemitter3\";\n\n/**\n * Job status in the lifecycle.\n */\nexport type JobStatus = \"queued\" | \"running\" | \"completed\" | \"failed\";\n\n/**\n * A job record representing an async tool invocation.\n */\nexport interface Job {\n jobId: string;\n toolName: string;\n requestId: string;\n taskId: string;\n status: JobStatus;\n createdAt: number; // epoch ms\n updatedAt: number;\n result?: unknown;\n error?: string;\n metadata?: Record<string, unknown>;\n}\n\n/**\n * Options for submitting a job.\n */\nexport interface SubmitJobOptions {\n toolName: string;\n requestId: string;\n taskId: string;\n metadata?: Record<string, unknown>;\n}\n\n/**\n * Job store interface for pluggable backends.\n */\nexport interface JobStore {\n set(jobId: string, job: Job): Promise<void>;\n get(jobId: string): Promise<Job | undefined>;\n list(filter?: { toolName?: string; status?: JobStatus }): Promise<Job[]>;\n delete(jobId: string): Promise<void>;\n}\n\n/**\n * In-memory job store (default, for PoC and testing).\n */\nexport class InMemoryJobStore implements JobStore {\n private readonly jobs = new Map<string, Job>();\n\n async set(jobId: string, job: Job): Promise<void> {\n this.jobs.set(jobId, job);\n }\n\n async get(jobId: string): Promise<Job | undefined> {\n return this.jobs.get(jobId);\n }\n\n async list(filter?: { toolName?: string; status?: JobStatus }): Promise<Job[]> {\n let results = [...this.jobs.values()];\n if (filter?.toolName) {\n results = results.filter((j) => j.toolName === filter.toolName);\n }\n if (filter?.status) {\n results = results.filter((j) => j.status === filter.status);\n }\n return results;\n }\n\n async delete(jobId: string): Promise<void> {\n this.jobs.delete(jobId);\n }\n\n get size(): number {\n return this.jobs.size;\n }\n\n clear(): void {\n this.jobs.clear();\n }\n}\n\n/**\n * Async Job Manager: unified async task handling for tools.\n * Provides submit/poll/getResult pattern.\n */\nexport class AsyncJobManager {\n private readonly store: JobStore;\n private readonly emitter = new EventEmitter();\n private readonly ttlMs: number;\n private cleanupTimer?: ReturnType<typeof setInterval>;\n\n constructor(options: { store?: JobStore; ttlMs?: number } = {}) {\n this.store = options.store ?? new InMemoryJobStore();\n this.ttlMs = options.ttlMs ?? 3600_000; // 1 hour default TTL\n this.startCleanup();\n }\n\n /**\n * Submit a new async job.\n */\n async submit(options: SubmitJobOptions): Promise<Job> {\n const now = Date.now();\n const job: Job = {\n jobId: uuidv4(),\n toolName: options.toolName,\n requestId: options.requestId,\n taskId: options.taskId,\n status: \"queued\",\n createdAt: now,\n updatedAt: now,\n metadata: options.metadata,\n };\n\n await this.store.set(job.jobId, job);\n this.emitter.emit(\"submitted\", job);\n return job;\n }\n\n /**\n * Update job status to running.\n */\n async markRunning(jobId: string): Promise<Job | undefined> {\n const job = await this.store.get(jobId);\n if (!job) return undefined;\n\n job.status = \"running\";\n job.updatedAt = Date.now();\n await this.store.set(jobId, job);\n this.emitter.emit(\"running\", job);\n return job;\n }\n\n /**\n * Complete a job with a result.\n */\n async complete(jobId: string, result: unknown): Promise<Job | undefined> {\n const job = await this.store.get(jobId);\n if (!job) return undefined;\n\n job.status = \"completed\";\n job.result = result;\n job.updatedAt = Date.now();\n await this.store.set(jobId, job);\n this.emitter.emit(\"completed\", job);\n return job;\n }\n\n /**\n * Fail a job with an error message.\n */\n async fail(jobId: string, error: string): Promise<Job | undefined> {\n const job = await this.store.get(jobId);\n if (!job) return undefined;\n\n job.status = \"failed\";\n job.error = error;\n job.updatedAt = Date.now();\n await this.store.set(jobId, job);\n this.emitter.emit(\"failed\", job);\n return job;\n }\n\n /**\n * Get current job status.\n */\n async getStatus(jobId: string): Promise<JobStatus | undefined> {\n const job = await this.store.get(jobId);\n return job?.status;\n }\n\n /**\n * Get the full job record.\n */\n async getJob(jobId: string): Promise<Job | undefined> {\n return this.store.get(jobId);\n }\n\n /**\n * Get the result of a completed job.\n */\n async getResult(jobId: string): Promise<unknown | undefined> {\n const job = await this.store.get(jobId);\n if (!job || job.status !== \"completed\") return undefined;\n return job.result;\n }\n\n /**\n * List jobs with optional filter.\n */\n async list(filter?: {\n toolName?: string;\n status?: JobStatus;\n }): Promise<Job[]> {\n return this.store.list(filter);\n }\n\n /**\n * Subscribe to job events.\n */\n on(\n event: \"submitted\" | \"running\" | \"completed\" | \"failed\",\n listener: (job: Job) => void,\n ): () => void {\n this.emitter.on(event, listener);\n return () => this.emitter.off(event, listener);\n }\n\n /**\n * Stop cleanup timer.\n */\n dispose(): void {\n if (this.cleanupTimer) {\n clearInterval(this.cleanupTimer);\n this.cleanupTimer = undefined;\n }\n }\n\n private startCleanup(): void {\n // Run cleanup every TTL/2 interval\n const interval = Math.max(this.ttlMs / 2, 60_000);\n this.cleanupTimer = setInterval(() => void this.cleanup(), interval);\n if (typeof this.cleanupTimer === \"object\" && \"unref\" in this.cleanupTimer) {\n this.cleanupTimer.unref();\n }\n }\n\n private async cleanup(): Promise<void> {\n const now = Date.now();\n const all = await this.store.list();\n for (const job of all) {\n if (\n (job.status === \"completed\" || job.status === \"failed\") &&\n now - job.updatedAt > this.ttlMs\n ) {\n await this.store.delete(job.jobId);\n }\n }\n }\n}\n","import type { ToolAdapter, ToolSpec } from \"../types/ToolSpec.js\";\nimport type { ExecContext } from \"../types/ToolIntent.js\";\nimport type { DirectoryScannerOptions } from \"./types.js\";\nimport type { DiscoverySource } from \"../registry/Discovery.js\";\nimport { DirectoryScanner } from \"./DirectoryScanner.js\";\n\n/**\n * A ToolAdapter that discovers tools from filesystem directories.\n * Used as the adapter within a DiscoverySource for the Discovery system.\n *\n * Note: This adapter's invoke() is not called directly. Discovered tools\n * retain their original kind (mcp/langchain/skill/n8n) and are invoked\n * by the kind-specific adapter registered on PTCRuntime.\n */\nexport class DirectoryToolAdapter implements ToolAdapter {\n readonly kind = \"mcp\" as const; // Required by ToolAdapter but not used for routing\n private readonly scanner: DirectoryScanner;\n\n constructor(options: DirectoryScannerOptions) {\n this.scanner = new DirectoryScanner(options);\n }\n\n /**\n * Scan directories and return discovered tool specs.\n * Called by Discovery.refresh().\n */\n async listTools(): Promise<ToolSpec[]> {\n return this.scanner.scan();\n }\n\n /**\n * Not used — actual invocation routes through kind-specific adapters.\n */\n async invoke(\n _spec: ToolSpec,\n _args: unknown,\n _ctx: ExecContext,\n ): Promise<{ result: unknown }> {\n throw new Error(\n \"DirectoryToolAdapter.invoke() should not be called directly. \" +\n \"Tool execution is handled by the kind-specific adapter (MCPAdapter, LangChainAdapter, etc.).\",\n );\n }\n\n /**\n * Get the underlying scanner for direct usage.\n */\n getScanner(): DirectoryScanner {\n return this.scanner;\n }\n}\n\n/**\n * Options for creating a directory discovery source.\n */\nexport interface DirectoryDiscoveryOptions extends DirectoryScannerOptions {\n /** Refresh interval in ms (0 = manual only, default: 0) */\n refreshIntervalMs?: number;\n /** Whether to auto-discover on startup (default: true) */\n autoDiscover?: boolean;\n}\n\n/**\n * Factory: create a DiscoverySource for directory-based tool discovery.\n *\n * Usage:\n * ```ts\n * const discovery = new Discovery(registry);\n * discovery.addSource(\n * createDirectoryDiscoverySource(\"local-tools\", {\n * roots: [\"/path/to/tools\"],\n * namespace: \"local\",\n * refreshIntervalMs: 60_000,\n * autoDiscover: true,\n * })\n * );\n * ```\n */\nexport function createDirectoryDiscoverySource(\n id: string,\n options: DirectoryDiscoveryOptions,\n): DiscoverySource {\n const { refreshIntervalMs, autoDiscover, ...scannerOptions } = options;\n\n return {\n id,\n adapter: new DirectoryToolAdapter(scannerOptions),\n refreshIntervalMs: refreshIntervalMs ?? 0,\n autoDiscover: autoDiscover ?? true,\n };\n}\n","import type { MCPServerConfig } from \"./types.js\";\n\n/**\n * Connection info for an MCP server.\n */\nexport interface MCPConnectionInfo {\n /** Transport type: \"url\" for SSE/HTTP, \"stdio\" for command-based */\n type: \"url\" | \"stdio\";\n /** SSE/HTTP URL (when type=\"url\") */\n url?: string;\n /** Command to spawn (when type=\"stdio\") */\n command?: string;\n /** Command arguments (when type=\"stdio\") */\n args?: string[];\n /** Environment variables (when type=\"stdio\") */\n env?: Record<string, string>;\n}\n\n/**\n * Manages MCP server connection information extracted from directory discovery.\n *\n * This class provides connection configuration for MCP servers discovered\n * from mcp.json files. The actual MCP client creation and lifecycle management\n * is the consumer's responsibility (using @modelcontextprotocol/sdk or similar).\n *\n * Usage:\n * ```ts\n * const manager = new MCPProcessManager();\n * const info = manager.getConnectionInfo(\"my-tool\", mcpConfig);\n * if (info.type === \"stdio\") {\n * // Spawn process with info.command, info.args, info.env\n * } else {\n * // Connect SSE client to info.url\n * }\n * ```\n */\nexport class MCPProcessManager {\n private readonly connections = new Map<string, MCPConnectionInfo>();\n\n /**\n * Get connection info for an MCP tool based on its config.\n * Caches the result by tool name.\n */\n getConnectionInfo(toolName: string, config: MCPServerConfig): MCPConnectionInfo {\n const cached = this.connections.get(toolName);\n if (cached) return cached;\n\n const info: MCPConnectionInfo = config.url\n ? { type: \"url\", url: config.url }\n : {\n type: \"stdio\",\n command: config.command!,\n args: config.args,\n env: config.env,\n };\n\n this.connections.set(toolName, info);\n return info;\n }\n\n /**\n * Remove cached connection info for a tool.\n */\n remove(toolName: string): boolean {\n return this.connections.delete(toolName);\n }\n\n /**\n * Get all registered tool names.\n */\n getToolNames(): string[] {\n return [...this.connections.keys()];\n }\n\n /**\n * Clear all cached connection info.\n */\n dispose(): void {\n this.connections.clear();\n }\n}\n"]}