@iworkforces/tracelattice 2.0.3 → 2.0.5
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +6 -12
- package/dist/cli.js +221 -2213
- package/dist/cli.js.map +1 -1
- package/dist/contracts/transport.d.ts +2 -2
- package/dist/contracts/transport.d.ts.map +1 -1
- package/dist/core/ThoughtProcessor.d.ts +1 -1
- package/dist/core/ThoughtProcessor.d.ts.map +1 -1
- package/dist/core/ThoughtProcessor.js +3 -6
- package/dist/core/ThoughtProcessor.js.map +1 -1
- package/dist/lib.d.ts +0 -10
- package/dist/lib.d.ts.map +1 -1
- package/dist/lib.js.map +1 -1
- package/dist/persistence/FileSnapshotV2.d.ts +2 -2
- package/dist/schema.d.ts +1 -1
- package/dist/schema.d.ts.map +1 -1
- package/dist/schema.js +4 -2
- package/dist/schema.js.map +1 -1
- package/dist/transport/HttpHelpers.d.ts +1 -1
- package/dist/transport/HttpHelpers.js.map +1 -1
- package/package.json +1 -1
- package/dist/transport/SseTransport.d.ts +0 -149
- package/dist/transport/SseTransport.d.ts.map +0 -1
- package/dist/transport/SseTransport.js +0 -470
- package/dist/transport/SseTransport.js.map +0 -1
package/dist/cli.js
CHANGED
|
@@ -1,20 +1,29 @@
|
|
|
1
1
|
#!/usr/bin/env bun
|
|
2
|
-
import * as
|
|
3
|
-
import * as __rspack_external_node_async_hooks_4d8b1b4a from "node:async_hooks";
|
|
2
|
+
import * as __rspack_external_valibot from "valibot";
|
|
4
3
|
import * as __rspack_external_node_crypto_2e7c4b46 from "node:crypto";
|
|
5
4
|
import * as __rspack_external_node_http_e245b239 from "node:http";
|
|
5
|
+
import * as __rspack_external_node_async_hooks_4d8b1b4a from "node:async_hooks";
|
|
6
|
+
import * as __rspack_external__tmcp_adapter_valibot_0faddfa6 from "@tmcp/adapter-valibot";
|
|
7
|
+
import * as __rspack_external__tmcp_transport_stdio_98e5584f from "@tmcp/transport-stdio";
|
|
8
|
+
import * as __rspack_external_node_fs_1b05aee1 from "node:fs";
|
|
9
|
+
import * as __rspack_external_node_path_806ed179 from "node:path";
|
|
6
10
|
import * as __rspack_external_node_url_3991086a from "node:url";
|
|
7
|
-
import * as
|
|
8
|
-
import
|
|
9
|
-
import { StdioTransport } from "@tmcp/transport-stdio";
|
|
10
|
-
import { existsSync, readFileSync } from "node:fs";
|
|
11
|
-
import { dirname, join } from "node:path";
|
|
12
|
-
import { McpServer } from "tmcp";
|
|
13
|
-
import { homedir } from "node:os";
|
|
14
|
-
import { parse } from "yaml";
|
|
11
|
+
import * as __rspack_external_tmcp from "tmcp";
|
|
12
|
+
import * as __rspack_external__lib_js_1645bc55 from "./lib.js";
|
|
15
13
|
var __webpack_modules__ = ({
|
|
16
|
-
"
|
|
17
|
-
|
|
14
|
+
"i"(__unused_rspack_module, __webpack_exports__, __webpack_require__) {
|
|
15
|
+
|
|
16
|
+
// EXPORTS
|
|
17
|
+
__webpack_require__.d(__webpack_exports__, {
|
|
18
|
+
RE: () => (/* binding */ getRequestId),
|
|
19
|
+
Vo: () => (/* binding */ runWithContext)
|
|
20
|
+
});
|
|
21
|
+
|
|
22
|
+
// UNUSED EXPORTS: getOwner
|
|
23
|
+
|
|
24
|
+
;// CONCATENATED MODULE: external "node:async_hooks"
|
|
25
|
+
|
|
26
|
+
;// CONCATENATED MODULE: ./src/context/RequestContext.ts
|
|
18
27
|
/**
|
|
19
28
|
* Request context management using AsyncLocalStorage for correlation IDs.
|
|
20
29
|
*
|
|
@@ -26,7 +35,7 @@ var __webpack_modules__ = ({
|
|
|
26
35
|
/**
|
|
27
36
|
* AsyncLocalStorage instance for request context.
|
|
28
37
|
* Stores requestId that propagates across async boundaries.
|
|
29
|
-
*/ const store = new
|
|
38
|
+
*/ const store = new __rspack_external_node_async_hooks_4d8b1b4a.AsyncLocalStorage();
|
|
30
39
|
/**
|
|
31
40
|
* Get the current request ID from context.
|
|
32
41
|
*
|
|
@@ -57,133 +66,6 @@ var __webpack_modules__ = ({
|
|
|
57
66
|
return store.getStore()?.owner;
|
|
58
67
|
}
|
|
59
68
|
|
|
60
|
-
__webpack_require__.d(__webpack_exports__, {
|
|
61
|
-
QQ: () => (getOwner),
|
|
62
|
-
RE: () => (getRequestId),
|
|
63
|
-
Vo: () => (runWithContext)
|
|
64
|
-
});
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
},
|
|
68
|
-
"j"(__unused_rspack_module, __webpack_exports__, __webpack_require__) {
|
|
69
|
-
/* import */ var _core_ids_js__rspack_import_0 = __webpack_require__("Uz");
|
|
70
|
-
/* import */ var _errors_js__rspack_import_1 = __webpack_require__("U");
|
|
71
|
-
/**
|
|
72
|
-
* Branded identifier types for compile-time slot safety.
|
|
73
|
-
*
|
|
74
|
-
* These nominal types prevent accidental mixing of different ID kinds
|
|
75
|
-
* (e.g. passing a `ThoughtId` where a `SessionId` is expected). At
|
|
76
|
-
* runtime they are plain strings — the brand exists only in the type
|
|
77
|
-
* system.
|
|
78
|
-
*
|
|
79
|
-
* @module contracts/ids
|
|
80
|
-
*/
|
|
81
|
-
|
|
82
|
-
/**
|
|
83
|
-
* Validate and brand a string as a {@link SessionId}.
|
|
84
|
-
*
|
|
85
|
-
* Enforces {@link SESSION_ID_PATTERN} and {@link MAX_SESSION_ID_LENGTH}.
|
|
86
|
-
* The reserved global session sentinel `__global__` is always accepted.
|
|
87
|
-
*
|
|
88
|
-
* @throws {ValidationError} when the input is not a valid session id.
|
|
89
|
-
*/ function asSessionId(value) {
|
|
90
|
-
if (value === '__global__') {
|
|
91
|
-
// eslint-disable-next-line no-restricted-syntax -- branding constructor, cannot self-reference
|
|
92
|
-
return value;
|
|
93
|
-
}
|
|
94
|
-
if (typeof value !== 'string' || value.length === 0) {
|
|
95
|
-
throw new _errors_js__rspack_import_1/* .ValidationError */.yI('session_id', 'must be a non-empty string');
|
|
96
|
-
}
|
|
97
|
-
if (value.length > (/* inlined export .MAX_SESSION_ID_LENGTH */100)) {
|
|
98
|
-
throw new _errors_js__rspack_import_1/* .ValidationError */.yI('session_id', `exceeds max length of ${(/* inlined export .MAX_SESSION_ID_LENGTH */100)}`);
|
|
99
|
-
}
|
|
100
|
-
if (!_core_ids_js__rspack_import_0/* .SESSION_ID_PATTERN.test */.I.test(value)) {
|
|
101
|
-
throw new _errors_js__rspack_import_1/* .ValidationError */.yI('session_id', 'must match alphanumeric, hyphens, underscores');
|
|
102
|
-
}
|
|
103
|
-
// eslint-disable-next-line no-restricted-syntax -- branding constructor, cannot self-reference
|
|
104
|
-
return value;
|
|
105
|
-
}
|
|
106
|
-
/** Brand a string as a {@link ThoughtId} without validation. */ function asThoughtId(value) {
|
|
107
|
-
return value;
|
|
108
|
-
}
|
|
109
|
-
/** Brand a string as an {@link EdgeId} without validation. */ function asEdgeId(value) {
|
|
110
|
-
return value;
|
|
111
|
-
}
|
|
112
|
-
/** Brand a string as a {@link SuspensionToken} without validation. */ function asSuspensionToken(value) {
|
|
113
|
-
return value;
|
|
114
|
-
}
|
|
115
|
-
/** Brand a string as a {@link BranchId} without validation. */ function asBranchId(value) {
|
|
116
|
-
return value;
|
|
117
|
-
}
|
|
118
|
-
/** Brand a string as a {@link SummaryId} without validation. */ function asSummaryId(value) {
|
|
119
|
-
return value;
|
|
120
|
-
}
|
|
121
|
-
/** Generate a fresh {@link ThoughtId}. */ function generateThoughtId() {
|
|
122
|
-
return generateUlid();
|
|
123
|
-
}
|
|
124
|
-
/** Generate a fresh {@link EdgeId}. */ function generateEdgeId() {
|
|
125
|
-
return generateUlid();
|
|
126
|
-
}
|
|
127
|
-
/** Generate a fresh {@link SuspensionToken}. */ function generateSuspensionToken() {
|
|
128
|
-
return generateUlid();
|
|
129
|
-
}
|
|
130
|
-
/** Generate a fresh {@link SummaryId}. */ function generateSummaryId() {
|
|
131
|
-
return generateUlid();
|
|
132
|
-
}
|
|
133
|
-
/**
|
|
134
|
-
* Reserved sentinel session id used when callers omit `session_id`.
|
|
135
|
-
*
|
|
136
|
-
* Branded once here so production and test code share one constant
|
|
137
|
-
* instead of casting `'__global__'` ad-hoc.
|
|
138
|
-
*/ const GLOBAL_SESSION_ID = asSessionId('__global__');
|
|
139
|
-
|
|
140
|
-
__webpack_require__.d(__webpack_exports__, {
|
|
141
|
-
Kd: () => (asSessionId)
|
|
142
|
-
});
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
},
|
|
146
|
-
"Uz"(__unused_rspack_module, __webpack_exports__, __webpack_require__) {
|
|
147
|
-
/* import */ var node_crypto__rspack_import_0 = __webpack_require__("i");
|
|
148
|
-
/**
|
|
149
|
-
* Unique identifier generation utilities for thoughts and edges.
|
|
150
|
-
*
|
|
151
|
-
* @module core/ids
|
|
152
|
-
*/
|
|
153
|
-
/**
|
|
154
|
-
* Generate a unique lexicographically-sortable identifier.
|
|
155
|
-
*
|
|
156
|
-
* Format: 8-char base36 timestamp + 20-char hex random (10 random bytes).
|
|
157
|
-
* Result is up to 28 characters, sortable by creation time.
|
|
158
|
-
*
|
|
159
|
-
* @returns A unique string identifier.
|
|
160
|
-
*
|
|
161
|
-
* @example
|
|
162
|
-
* ```typescript
|
|
163
|
-
* const id = generateUlid(); // '01h2k3m400a1b2c3d4e5f6...'
|
|
164
|
-
* ```
|
|
165
|
-
*/ function generateUlid() {
|
|
166
|
-
const timestamp = Date.now().toString(36).padStart(8, '0');
|
|
167
|
-
const random = crypto.randomBytes(10).toString('hex');
|
|
168
|
-
return `${timestamp}${random}`;
|
|
169
|
-
}
|
|
170
|
-
/**
|
|
171
|
-
* Valid session ID pattern: alphanumeric, hyphens, underscores.
|
|
172
|
-
*
|
|
173
|
-
* Length is enforced separately via {@link MAX_SESSION_ID_LENGTH}.
|
|
174
|
-
* Same character set as branch IDs.
|
|
175
|
-
*/ const SESSION_ID_PATTERN = /^[a-zA-Z0-9_-]+$/;
|
|
176
|
-
/**
|
|
177
|
-
* Maximum session ID length (in characters).
|
|
178
|
-
*
|
|
179
|
-
* Allows compound identifiers (e.g. `user-123_task-abc`).
|
|
180
|
-
*/ const MAX_SESSION_ID_LENGTH = 100;
|
|
181
|
-
|
|
182
|
-
__webpack_require__.d(__webpack_exports__, {
|
|
183
|
-
}, {
|
|
184
|
-
I: SESSION_ID_PATTERN
|
|
185
|
-
});
|
|
186
|
-
|
|
187
69
|
|
|
188
70
|
},
|
|
189
71
|
"U"(__unused_rspack_module, __webpack_exports__, __webpack_require__) {
|
|
@@ -920,550 +802,68 @@ class PersistenceClosedError extends SequentialThinkingError {
|
|
|
920
802
|
|
|
921
803
|
__webpack_require__.d(__webpack_exports__, {
|
|
922
804
|
Qt: () => (CliShutdownTimeoutError),
|
|
923
|
-
j1: () => (ConfigurationError),
|
|
924
|
-
m_: () => (PoolTerminatedError),
|
|
925
|
-
oN: () => (SequentialThinkingError),
|
|
926
805
|
u1: () => (getErrorMessage),
|
|
927
|
-
yI: () => (ValidationError)
|
|
928
|
-
yM: () => (MaxSessionsReachedError)
|
|
929
|
-
}, {
|
|
930
|
-
OQ: ERROR_CODES
|
|
806
|
+
yI: () => (ValidationError)
|
|
931
807
|
});
|
|
932
808
|
|
|
933
809
|
|
|
934
810
|
},
|
|
935
|
-
"
|
|
936
|
-
/* import */ var
|
|
937
|
-
/* import */ var _errors_js__rspack_import_1 = __webpack_require__("U");
|
|
938
|
-
/* import */ var _contracts_ids_js__rspack_import_2 = __webpack_require__("j");
|
|
939
|
-
/* import */ var _utils_js__rspack_import_4 = __webpack_require__("h");
|
|
940
|
-
/* import */ var _PoolErrors_js__rspack_import_3 = __webpack_require__("K");
|
|
811
|
+
"R"(__unused_rspack_module, __webpack_exports__, __webpack_require__) {
|
|
812
|
+
/* import */ var valibot__rspack_import_0 = __webpack_require__("w");
|
|
941
813
|
/**
|
|
942
|
-
*
|
|
814
|
+
* Valibot validation schemas for the sequential thinking MCP tool.
|
|
815
|
+
*
|
|
816
|
+
* This module defines the validation schemas used for the sequential thinking tool,
|
|
817
|
+
* including schemas for tool recommendations, skill recommendations, step recommendations,
|
|
818
|
+
* and the main sequential thinking input. All schemas use Valibot for runtime validation
|
|
819
|
+
* and provide detailed descriptions for MCP protocol compatibility.
|
|
943
820
|
*
|
|
944
|
-
*
|
|
945
|
-
*
|
|
821
|
+
* @remarks
|
|
822
|
+
* **Schema Overview:**
|
|
823
|
+
* - `ToolRecommendationSchema` - Validates tool recommendation objects with confidence scores
|
|
824
|
+
* - `SkillRecommendationSchema` - Validates skill recommendation objects
|
|
825
|
+
* - `StepRecommendationSchema` - Validates step coordination structures
|
|
826
|
+
* - `SequentialThinkingSchema` - Main schema for thought input validation
|
|
827
|
+
* - Reasoning enhancement fields: thought_type, quality_score, confidence, hypothesis_id, etc.
|
|
946
828
|
*
|
|
947
829
|
* @example
|
|
948
830
|
* ```typescript
|
|
949
|
-
*
|
|
950
|
-
*
|
|
951
|
-
* sessionTimeout: 300000 // 5 minutes
|
|
952
|
-
* });
|
|
831
|
+
* import { SequentialThinkingSchema } from './schema.js';
|
|
832
|
+
* import { safeParse } from 'valibot';
|
|
953
833
|
*
|
|
954
|
-
* const
|
|
955
|
-
*
|
|
956
|
-
*
|
|
834
|
+
* const result = safeParse(SequentialThinkingSchema, inputData);
|
|
835
|
+
* if (result.success) {
|
|
836
|
+
* const thought = result.output;
|
|
837
|
+
* // Process the valid thought
|
|
838
|
+
* } else {
|
|
839
|
+
* console.error('Validation failed:', result.issues);
|
|
840
|
+
* }
|
|
957
841
|
* ```
|
|
842
|
+
* @module schema
|
|
958
843
|
*/
|
|
844
|
+
/**
|
|
845
|
+
* Detailed description for the sequential thinking tool.
|
|
846
|
+
*
|
|
847
|
+
* This description is shown to LLMs when they consider using this tool.
|
|
848
|
+
* It explains when to use the tool, its features, parameters, and best practices.
|
|
849
|
+
*/ const TOOL_DESCRIPTION = `A detailed tool for dynamic and reflective problem-solving through thoughts.
|
|
850
|
+
This tool helps analyze problems through a flexible thinking process that can adapt and evolve.
|
|
851
|
+
Each thought can build on, question, or revise previous insights as understanding deepens.
|
|
959
852
|
|
|
853
|
+
IMPORTANT: This server facilitates sequential thinking with MCP tool coordination and skill recommendations. The LLM analyzes available tools and skills to make intelligent recommendations, which are then tracked and organized by this server.
|
|
960
854
|
|
|
855
|
+
Each invocation records exactly one authored thought and returns. When strategy_hint.action is continue, invoke this tool again with the next thought; do not stop or provide a final answer. terminate permits stopping. The server does not author later thoughts or call itself.
|
|
961
856
|
|
|
962
|
-
|
|
963
|
-
|
|
964
|
-
|
|
965
|
-
|
|
966
|
-
|
|
967
|
-
|
|
968
|
-
|
|
969
|
-
|
|
970
|
-
|
|
971
|
-
|
|
972
|
-
_cleanupTimer = null;
|
|
973
|
-
_logger;
|
|
974
|
-
_closePromise = null;
|
|
975
|
-
_activeOperationCount = 0;
|
|
976
|
-
_operationDrain = null;
|
|
977
|
-
constructor(id, server, timeout, logger){
|
|
978
|
-
this._server = server;
|
|
979
|
-
this._id = id;
|
|
980
|
-
this._createdAt = Date.now();
|
|
981
|
-
this._lastActivityAt = this._createdAt;
|
|
982
|
-
this._isActiveValue = true;
|
|
983
|
-
this._timeout = timeout;
|
|
984
|
-
this._logger = logger;
|
|
985
|
-
// Start session timeout timer
|
|
986
|
-
this._startTimeout();
|
|
987
|
-
}
|
|
988
|
-
/**
|
|
989
|
-
* Check if the session is active.
|
|
990
|
-
*/ get isActive() {
|
|
991
|
-
return this._isActiveValue;
|
|
992
|
-
}
|
|
993
|
-
/**
|
|
994
|
-
* Process a thought through this session's server instance.
|
|
995
|
-
*/ async process(input) {
|
|
996
|
-
if (!this.isActive) {
|
|
997
|
-
throw new _PoolErrors_js__rspack_import_3/* .SessionNotActiveError */.q(this._id);
|
|
998
|
-
}
|
|
999
|
-
// Update last activity
|
|
1000
|
-
this._lastActivityAt = Date.now();
|
|
1001
|
-
// Reset timeout timer
|
|
1002
|
-
this._resetTimeout();
|
|
1003
|
-
// Process the thought
|
|
1004
|
-
return this._server.processThought(input);
|
|
1005
|
-
}
|
|
1006
|
-
processAdmitted(input) {
|
|
1007
|
-
this._lastActivityAt = Date.now();
|
|
1008
|
-
if (this.isActive) this._resetTimeout();
|
|
1009
|
-
return this._server.processThought(input);
|
|
1010
|
-
}
|
|
1011
|
-
runWhileActive(operation) {
|
|
1012
|
-
if (!this.isActive) return Promise.resolve({
|
|
1013
|
-
status: 'inactive'
|
|
1014
|
-
});
|
|
1015
|
-
this._activeOperationCount++;
|
|
1016
|
-
return (async ()=>{
|
|
1017
|
-
try {
|
|
1018
|
-
return {
|
|
1019
|
-
status: 'completed',
|
|
1020
|
-
value: await operation(this)
|
|
1021
|
-
};
|
|
1022
|
-
} finally{
|
|
1023
|
-
this._activeOperationCount--;
|
|
1024
|
-
if (this._activeOperationCount === 0) this._operationDrain?.resolve();
|
|
1025
|
-
}
|
|
1026
|
-
})();
|
|
1027
|
-
}
|
|
1028
|
-
/**
|
|
1029
|
-
* Get session information.
|
|
1030
|
-
*/ getInfo() {
|
|
1031
|
-
return {
|
|
1032
|
-
id: this._id,
|
|
1033
|
-
server: this._server,
|
|
1034
|
-
createdAt: this._createdAt,
|
|
1035
|
-
lastActivityAt: this._lastActivityAt,
|
|
1036
|
-
isActive: this.isActive
|
|
1037
|
-
};
|
|
1038
|
-
}
|
|
1039
|
-
/**
|
|
1040
|
-
* Check if the session has timed out.
|
|
1041
|
-
*/ isTimedOut() {
|
|
1042
|
-
return Date.now() - this._lastActivityAt > this._timeout;
|
|
1043
|
-
}
|
|
1044
|
-
/**
|
|
1045
|
-
* Close the session and stop the server.
|
|
1046
|
-
*/ close() {
|
|
1047
|
-
if (this._closePromise) {
|
|
1048
|
-
return this._closePromise;
|
|
1049
|
-
}
|
|
1050
|
-
const completion = Promise.withResolvers();
|
|
1051
|
-
this._closePromise = completion.promise;
|
|
1052
|
-
this._isActiveValue = false;
|
|
1053
|
-
// Stop timeout timer
|
|
1054
|
-
if (this._cleanupTimer) {
|
|
1055
|
-
clearTimeout(this._cleanupTimer);
|
|
1056
|
-
this._cleanupTimer = null;
|
|
1057
|
-
}
|
|
1058
|
-
if (this._activeOperationCount === 0) {
|
|
1059
|
-
this._stopServer(completion);
|
|
1060
|
-
} else {
|
|
1061
|
-
this._operationDrain = Promise.withResolvers();
|
|
1062
|
-
void this._operationDrain.promise.then(()=>this._stopServer(completion));
|
|
1063
|
-
}
|
|
1064
|
-
return completion.promise;
|
|
1065
|
-
}
|
|
1066
|
-
_stopServer(completion) {
|
|
1067
|
-
try {
|
|
1068
|
-
Promise.resolve(this._server.stop()).then(completion.resolve, completion.reject);
|
|
1069
|
-
} catch (error) {
|
|
1070
|
-
completion.reject(error instanceof Error ? error : new AggregateError([
|
|
1071
|
-
error
|
|
1072
|
-
], 'Session stop failed'));
|
|
1073
|
-
}
|
|
1074
|
-
}
|
|
1075
|
-
/**
|
|
1076
|
-
* Start the session timeout timer.
|
|
1077
|
-
*/ _startTimeout() {
|
|
1078
|
-
if (this._cleanupTimer) {
|
|
1079
|
-
clearTimeout(this._cleanupTimer);
|
|
1080
|
-
}
|
|
1081
|
-
this._cleanupTimer = setTimeout(()=>{
|
|
1082
|
-
if (this.isTimedOut()) {
|
|
1083
|
-
this._logger.warn(`Session ${this._id} timed out, closing`);
|
|
1084
|
-
this.close().catch((err)=>{
|
|
1085
|
-
this._logger.error(`Error closing timed out session ${this._id}:`, err);
|
|
1086
|
-
});
|
|
1087
|
-
}
|
|
1088
|
-
}, this._timeout);
|
|
1089
|
-
}
|
|
1090
|
-
/**
|
|
1091
|
-
* Reset the timeout timer after activity.
|
|
1092
|
-
*/ _resetTimeout() {
|
|
1093
|
-
this._startTimeout();
|
|
1094
|
-
}
|
|
1095
|
-
}
|
|
1096
|
-
/**
|
|
1097
|
-
* ConnectionPool manages multiple concurrent user sessions.
|
|
1098
|
-
*
|
|
1099
|
-
* Each session has its own server instance with isolated state,
|
|
1100
|
-
* allowing multiple users to interact with the system simultaneously.
|
|
1101
|
-
*/ class ConnectionPool {
|
|
1102
|
-
_sessions = new Map();
|
|
1103
|
-
_closingSessions = new Map();
|
|
1104
|
-
_createSessionLock = null;
|
|
1105
|
-
_maxSessions;
|
|
1106
|
-
_sessionTimeout;
|
|
1107
|
-
_autoCleanup;
|
|
1108
|
-
_cleanupInterval;
|
|
1109
|
-
_cleanupTimerId = null;
|
|
1110
|
-
_terminated = false;
|
|
1111
|
-
_logger;
|
|
1112
|
-
_serverFactory;
|
|
1113
|
-
_terminatePromise = null;
|
|
1114
|
-
_admissionContext = new node_async_hooks__rspack_import_0.AsyncLocalStorage();
|
|
1115
|
-
_pendingCreateStopFailures = new Set();
|
|
1116
|
-
constructor(options = {}){
|
|
1117
|
-
this._maxSessions = options.maxSessions ?? 100;
|
|
1118
|
-
this._sessionTimeout = options.sessionTimeout ?? 300000; // 5 minutes
|
|
1119
|
-
this._autoCleanup = options.autoCleanup ?? true;
|
|
1120
|
-
this._cleanupInterval = options.cleanupInterval ?? 60000; // 1 minute
|
|
1121
|
-
this._serverFactory = options.serverFactory ?? null;
|
|
1122
|
-
this._logger = options.logger ?? this._createNoopLogger();
|
|
1123
|
-
if (this._autoCleanup) {
|
|
1124
|
-
this._startCleanup();
|
|
1125
|
-
}
|
|
1126
|
-
}
|
|
1127
|
-
/**
|
|
1128
|
-
* Create a no-op logger when none is provided.
|
|
1129
|
-
*/ _createNoopLogger() {
|
|
1130
|
-
return {
|
|
1131
|
-
info: ()=>{},
|
|
1132
|
-
warn: ()=>{},
|
|
1133
|
-
error: ()=>{},
|
|
1134
|
-
debug: ()=>{},
|
|
1135
|
-
setLevel: ()=>{},
|
|
1136
|
-
getLevel: ()=>'info'
|
|
1137
|
-
};
|
|
1138
|
-
}
|
|
1139
|
-
/**
|
|
1140
|
-
* Create a new session.
|
|
1141
|
-
*
|
|
1142
|
-
* @returns The session ID
|
|
1143
|
-
* @throws Error if max sessions reached
|
|
1144
|
-
*/ async createSession() {
|
|
1145
|
-
while(this._createSessionLock){
|
|
1146
|
-
await this._createSessionLock;
|
|
1147
|
-
}
|
|
1148
|
-
if (this._terminated) {
|
|
1149
|
-
throw new _errors_js__rspack_import_1/* .PoolTerminatedError */.m_();
|
|
1150
|
-
}
|
|
1151
|
-
if (this._sessions.size >= this._maxSessions) {
|
|
1152
|
-
throw new _errors_js__rspack_import_1/* .MaxSessionsReachedError */.yM(this._maxSessions);
|
|
1153
|
-
}
|
|
1154
|
-
if (!this._serverFactory) {
|
|
1155
|
-
throw new Error('ConnectionPool requires a serverFactory option to create sessions');
|
|
1156
|
-
}
|
|
1157
|
-
let resolveLock;
|
|
1158
|
-
this._createSessionLock = new Promise((resolve)=>{
|
|
1159
|
-
resolveLock = resolve;
|
|
1160
|
-
});
|
|
1161
|
-
try {
|
|
1162
|
-
// Generate unique session ID
|
|
1163
|
-
const sessionId = (0,_contracts_ids_js__rspack_import_2/* .asSessionId */.Kd)(`session_${Date.now()}_${Math.random().toString(36).substring(2, 11)}`);
|
|
1164
|
-
// Create a new server instance for this session
|
|
1165
|
-
const server = await this._serverFactory();
|
|
1166
|
-
if (this._terminated) {
|
|
1167
|
-
try {
|
|
1168
|
-
await server.stop();
|
|
1169
|
-
} catch (error) {
|
|
1170
|
-
this._pendingCreateStopFailures.add(error);
|
|
1171
|
-
throw error;
|
|
1172
|
-
}
|
|
1173
|
-
throw new _errors_js__rspack_import_1/* .PoolTerminatedError */.m_();
|
|
1174
|
-
}
|
|
1175
|
-
// Create session
|
|
1176
|
-
const session = new Session(sessionId, server, this._sessionTimeout, this._logger);
|
|
1177
|
-
this._sessions.set(sessionId, session);
|
|
1178
|
-
this._logger.info(`Created session ${sessionId} (${this._sessions.size}/${this._maxSessions} active sessions)`);
|
|
1179
|
-
return sessionId;
|
|
1180
|
-
} finally{
|
|
1181
|
-
resolveLock();
|
|
1182
|
-
this._createSessionLock = null;
|
|
1183
|
-
}
|
|
1184
|
-
}
|
|
1185
|
-
/**
|
|
1186
|
-
* Process a thought in the specified session.
|
|
1187
|
-
*
|
|
1188
|
-
* @param sessionId - The session ID
|
|
1189
|
-
* @param input - The thought data to process
|
|
1190
|
-
* @returns Promise with the processing result
|
|
1191
|
-
* @throws Error if session not found
|
|
1192
|
-
*/ async process(sessionId, input) {
|
|
1193
|
-
const result = await this._runWithSession(sessionId, (session)=>session.processAdmitted(input));
|
|
1194
|
-
switch(result.status){
|
|
1195
|
-
case 'completed':
|
|
1196
|
-
return result.value;
|
|
1197
|
-
case 'inactive':
|
|
1198
|
-
throw new _PoolErrors_js__rspack_import_3/* .SessionNotActiveError */.q(sessionId);
|
|
1199
|
-
case 'missing':
|
|
1200
|
-
throw new _PoolErrors_js__rspack_import_3/* .SessionNotFoundError */.A(sessionId);
|
|
1201
|
-
default:
|
|
1202
|
-
return (0,_utils_js__rspack_import_4/* .assertNever */.x)(result);
|
|
1203
|
-
}
|
|
1204
|
-
}
|
|
1205
|
-
runWithSession(sessionId, operation) {
|
|
1206
|
-
return this._runWithSession(sessionId, (session)=>operation(session.getInfo().server));
|
|
1207
|
-
}
|
|
1208
|
-
_runWithSession(sessionId, operation) {
|
|
1209
|
-
const activeFrame = this._admissionContext.getStore();
|
|
1210
|
-
if (activeFrame?.open === true && activeFrame.sessionId === sessionId) {
|
|
1211
|
-
return (async ()=>({
|
|
1212
|
-
status: 'completed',
|
|
1213
|
-
value: await operation(activeFrame.session)
|
|
1214
|
-
}))();
|
|
1215
|
-
}
|
|
1216
|
-
const session = this._sessions.get(sessionId);
|
|
1217
|
-
if (!session) {
|
|
1218
|
-
return Promise.resolve(this._closingSessions.has(sessionId) ? {
|
|
1219
|
-
status: 'inactive'
|
|
1220
|
-
} : {
|
|
1221
|
-
status: 'missing'
|
|
1222
|
-
});
|
|
1223
|
-
}
|
|
1224
|
-
return session.runWhileActive((capturedSession)=>{
|
|
1225
|
-
const frame = {
|
|
1226
|
-
sessionId,
|
|
1227
|
-
session: capturedSession,
|
|
1228
|
-
open: true
|
|
1229
|
-
};
|
|
1230
|
-
return this._admissionContext.run(frame, async ()=>{
|
|
1231
|
-
try {
|
|
1232
|
-
return await operation(capturedSession);
|
|
1233
|
-
} finally{
|
|
1234
|
-
frame.open = false;
|
|
1235
|
-
}
|
|
1236
|
-
});
|
|
1237
|
-
});
|
|
1238
|
-
}
|
|
1239
|
-
/**
|
|
1240
|
-
* Close a session and release resources.
|
|
1241
|
-
*
|
|
1242
|
-
* @param sessionId - The session ID to close
|
|
1243
|
-
* @throws Error if session not found
|
|
1244
|
-
*/ closeSession(sessionId) {
|
|
1245
|
-
const closing = this._closingSessions.get(sessionId);
|
|
1246
|
-
if (closing) {
|
|
1247
|
-
return closing;
|
|
1248
|
-
}
|
|
1249
|
-
const session = this._sessions.get(sessionId);
|
|
1250
|
-
if (!session) {
|
|
1251
|
-
return Promise.reject(new _PoolErrors_js__rspack_import_3/* .SessionNotFoundError */.A(sessionId));
|
|
1252
|
-
}
|
|
1253
|
-
this._sessions.delete(sessionId);
|
|
1254
|
-
const closePromise = session.close();
|
|
1255
|
-
this._closingSessions.set(sessionId, closePromise);
|
|
1256
|
-
void closePromise.then(()=>{
|
|
1257
|
-
this._closingSessions.delete(sessionId);
|
|
1258
|
-
this._logger.info(`Closed session ${sessionId} (${this._sessions.size}/${this._maxSessions} active sessions)`);
|
|
1259
|
-
}, ()=>{
|
|
1260
|
-
this._closingSessions.delete(sessionId);
|
|
1261
|
-
});
|
|
1262
|
-
return closePromise;
|
|
1263
|
-
}
|
|
1264
|
-
/**
|
|
1265
|
-
* Get information about a session.
|
|
1266
|
-
*
|
|
1267
|
-
* @param sessionId - The session ID
|
|
1268
|
-
* @returns Session info or undefined if not found
|
|
1269
|
-
*/ getSessionInfo(sessionId) {
|
|
1270
|
-
return this._sessions.get(sessionId)?.getInfo();
|
|
1271
|
-
}
|
|
1272
|
-
/**
|
|
1273
|
-
* Get all active sessions.
|
|
1274
|
-
*
|
|
1275
|
-
* @returns Array of session information
|
|
1276
|
-
*/ getActiveSessions() {
|
|
1277
|
-
return Array.from(this._sessions.values()).filter((s)=>s.isActive).map((s)=>s.getInfo());
|
|
1278
|
-
}
|
|
1279
|
-
/**
|
|
1280
|
-
* Get connection pool statistics.
|
|
1281
|
-
*/ getStats() {
|
|
1282
|
-
const activeSessions = this.getActiveSessions();
|
|
1283
|
-
return {
|
|
1284
|
-
totalSessions: this._sessions.size,
|
|
1285
|
-
activeSessions: activeSessions.length,
|
|
1286
|
-
maxSessions: this._maxSessions,
|
|
1287
|
-
cleanupEnabled: this._autoCleanup,
|
|
1288
|
-
sessionTimeout: this._sessionTimeout
|
|
1289
|
-
};
|
|
1290
|
-
}
|
|
1291
|
-
/**
|
|
1292
|
-
* Start the automatic cleanup timer.
|
|
1293
|
-
*/ _startCleanup() {
|
|
1294
|
-
if (this._cleanupTimerId !== null) {
|
|
1295
|
-
clearInterval(this._cleanupTimerId);
|
|
1296
|
-
}
|
|
1297
|
-
this._cleanupTimerId = setInterval(()=>{
|
|
1298
|
-
this._cleanupTimedOutSessions();
|
|
1299
|
-
}, this._cleanupInterval);
|
|
1300
|
-
}
|
|
1301
|
-
/**
|
|
1302
|
-
* Remove timed-out sessions.
|
|
1303
|
-
*/ _cleanupTimedOutSessions() {
|
|
1304
|
-
let cleaned = 0;
|
|
1305
|
-
for (const [sessionId, session] of this._sessions.entries()){
|
|
1306
|
-
if (session.isTimedOut()) {
|
|
1307
|
-
this.closeSession(sessionId).catch((err)=>{
|
|
1308
|
-
this._logger.error(`Error closing timed out session ${sessionId}:`, err);
|
|
1309
|
-
});
|
|
1310
|
-
cleaned++;
|
|
1311
|
-
}
|
|
1312
|
-
}
|
|
1313
|
-
if (cleaned > 0) {
|
|
1314
|
-
this._logger.info(`Cleaned ${cleaned} timed-out sessions (${this._sessions.size}/${this._maxSessions} active sessions)`);
|
|
1315
|
-
}
|
|
1316
|
-
}
|
|
1317
|
-
/**
|
|
1318
|
-
* Close all sessions and stop the cleanup timer.
|
|
1319
|
-
*/ terminate() {
|
|
1320
|
-
if (this._terminatePromise) {
|
|
1321
|
-
return this._terminatePromise;
|
|
1322
|
-
}
|
|
1323
|
-
const completion = Promise.withResolvers();
|
|
1324
|
-
this._terminatePromise = completion.promise;
|
|
1325
|
-
this._terminated = true;
|
|
1326
|
-
// Stop cleanup timer
|
|
1327
|
-
if (this._cleanupTimerId !== null) {
|
|
1328
|
-
clearInterval(this._cleanupTimerId);
|
|
1329
|
-
this._cleanupTimerId = null;
|
|
1330
|
-
}
|
|
1331
|
-
const sessions = Array.from(this._sessions.values());
|
|
1332
|
-
this._sessions.clear();
|
|
1333
|
-
const closePromises = new Set(this._closingSessions.values());
|
|
1334
|
-
if (this._createSessionLock) {
|
|
1335
|
-
closePromises.add(this._createSessionLock);
|
|
1336
|
-
}
|
|
1337
|
-
for (const session of sessions){
|
|
1338
|
-
closePromises.add(session.close());
|
|
1339
|
-
}
|
|
1340
|
-
void Promise.allSettled(closePromises).then((outcomes)=>{
|
|
1341
|
-
const failures = [
|
|
1342
|
-
...this._pendingCreateStopFailures,
|
|
1343
|
-
...outcomes.filter((outcome)=>outcome.status === 'rejected').map((outcome)=>outcome.reason)
|
|
1344
|
-
];
|
|
1345
|
-
if (failures.length > 0) {
|
|
1346
|
-
completion.reject(new AggregateError(failures, 'ConnectionPool termination failed'));
|
|
1347
|
-
return;
|
|
1348
|
-
}
|
|
1349
|
-
this._logger.info('ConnectionPool terminated');
|
|
1350
|
-
completion.resolve();
|
|
1351
|
-
});
|
|
1352
|
-
return completion.promise;
|
|
1353
|
-
}
|
|
1354
|
-
/**
|
|
1355
|
-
* Dispose of the connection pool, releasing all resources.
|
|
1356
|
-
* Implements the IDisposable interface.
|
|
1357
|
-
* Delegates to terminate() for backward compatibility.
|
|
1358
|
-
*/ dispose() {
|
|
1359
|
-
return this.terminate();
|
|
1360
|
-
}
|
|
1361
|
-
/**
|
|
1362
|
-
* Check if the connection pool is active.
|
|
1363
|
-
*/ isRunning() {
|
|
1364
|
-
return !this._terminated;
|
|
1365
|
-
}
|
|
1366
|
-
}
|
|
1367
|
-
/**
|
|
1368
|
-
* Create a connection pool with the given options.
|
|
1369
|
-
*
|
|
1370
|
-
* @param options - Connection pool configuration
|
|
1371
|
-
* @returns A configured connection pool
|
|
1372
|
-
*
|
|
1373
|
-
* @example
|
|
1374
|
-
* ```typescript
|
|
1375
|
-
* const pool = createConnectionPool({
|
|
1376
|
-
* maxSessions: 50,
|
|
1377
|
-
* sessionTimeout: 300000
|
|
1378
|
-
* });
|
|
1379
|
-
* ```
|
|
1380
|
-
*/ function createConnectionPool(options) {
|
|
1381
|
-
return new ConnectionPool(options);
|
|
1382
|
-
}
|
|
1383
|
-
|
|
1384
|
-
__webpack_require__.d(__webpack_exports__, {
|
|
1385
|
-
createConnectionPool: () => (createConnectionPool)
|
|
1386
|
-
});
|
|
1387
|
-
|
|
1388
|
-
|
|
1389
|
-
},
|
|
1390
|
-
"K"(__unused_rspack_module, __webpack_exports__, __webpack_require__) {
|
|
1391
|
-
/* import */ var _errors_js__rspack_import_0 = __webpack_require__("U");
|
|
1392
|
-
|
|
1393
|
-
/** Error thrown when attempting to process a session that is not active. */ class SessionNotActiveError extends _errors_js__rspack_import_0/* .SequentialThinkingError */.oN {
|
|
1394
|
-
constructor(sessionId){
|
|
1395
|
-
super(`Session '${sessionId}' is not active`, _errors_js__rspack_import_0/* .ERROR_CODES.SESSION_NOT_ACTIVE */.OQ.SESSION_NOT_ACTIVE);
|
|
1396
|
-
this.name = 'SessionNotActiveError';
|
|
1397
|
-
}
|
|
1398
|
-
}
|
|
1399
|
-
/** Error thrown when a requested session is not found in the pool. */ class SessionNotFoundError extends _errors_js__rspack_import_0/* .SequentialThinkingError */.oN {
|
|
1400
|
-
constructor(sessionId){
|
|
1401
|
-
super(`Session not found: ${sessionId}`, _errors_js__rspack_import_0/* .ERROR_CODES.SESSION_NOT_FOUND */.OQ.SESSION_NOT_FOUND);
|
|
1402
|
-
this.name = 'SessionNotFoundError';
|
|
1403
|
-
}
|
|
1404
|
-
}
|
|
1405
|
-
|
|
1406
|
-
__webpack_require__.d(__webpack_exports__, {
|
|
1407
|
-
A: () => (SessionNotFoundError),
|
|
1408
|
-
q: () => (SessionNotActiveError)
|
|
1409
|
-
});
|
|
1410
|
-
|
|
1411
|
-
|
|
1412
|
-
},
|
|
1413
|
-
"R"(__unused_rspack_module, __webpack_exports__, __webpack_require__) {
|
|
1414
|
-
/* import */ var valibot__rspack_import_0 = __webpack_require__("w");
|
|
1415
|
-
/**
|
|
1416
|
-
* Valibot validation schemas for the sequential thinking MCP tool.
|
|
1417
|
-
*
|
|
1418
|
-
* This module defines the validation schemas used for the sequential thinking tool,
|
|
1419
|
-
* including schemas for tool recommendations, skill recommendations, step recommendations,
|
|
1420
|
-
* and the main sequential thinking input. All schemas use Valibot for runtime validation
|
|
1421
|
-
* and provide detailed descriptions for MCP protocol compatibility.
|
|
1422
|
-
*
|
|
1423
|
-
* @remarks
|
|
1424
|
-
* **Schema Overview:**
|
|
1425
|
-
* - `ToolRecommendationSchema` - Validates tool recommendation objects with confidence scores
|
|
1426
|
-
* - `SkillRecommendationSchema` - Validates skill recommendation objects
|
|
1427
|
-
* - `StepRecommendationSchema` - Validates step coordination structures
|
|
1428
|
-
* - `SequentialThinkingSchema` - Main schema for thought input validation
|
|
1429
|
-
* - Reasoning enhancement fields: thought_type, quality_score, confidence, hypothesis_id, etc.
|
|
1430
|
-
*
|
|
1431
|
-
* @example
|
|
1432
|
-
* ```typescript
|
|
1433
|
-
* import { SequentialThinkingSchema } from './schema.js';
|
|
1434
|
-
* import { safeParse } from 'valibot';
|
|
1435
|
-
*
|
|
1436
|
-
* const result = safeParse(SequentialThinkingSchema, inputData);
|
|
1437
|
-
* if (result.success) {
|
|
1438
|
-
* const thought = result.output;
|
|
1439
|
-
* // Process the valid thought
|
|
1440
|
-
* } else {
|
|
1441
|
-
* console.error('Validation failed:', result.issues);
|
|
1442
|
-
* }
|
|
1443
|
-
* ```
|
|
1444
|
-
* @module schema
|
|
1445
|
-
*/
|
|
1446
|
-
/**
|
|
1447
|
-
* Detailed description for the sequential thinking tool.
|
|
1448
|
-
*
|
|
1449
|
-
* This description is shown to LLMs when they consider using this tool.
|
|
1450
|
-
* It explains when to use the tool, its features, parameters, and best practices.
|
|
1451
|
-
*/ const TOOL_DESCRIPTION = `A detailed tool for dynamic and reflective problem-solving through thoughts.
|
|
1452
|
-
This tool helps analyze problems through a flexible thinking process that can adapt and evolve.
|
|
1453
|
-
Each thought can build on, question, or revise previous insights as understanding deepens.
|
|
1454
|
-
|
|
1455
|
-
IMPORTANT: This server facilitates sequential thinking with MCP tool coordination and skill recommendations. The LLM analyzes available tools and skills to make intelligent recommendations, which are then tracked and organized by this server.
|
|
1456
|
-
|
|
1457
|
-
When to use this tool:
|
|
1458
|
-
- Breaking down complex problems into steps
|
|
1459
|
-
- Planning and design with room for revision
|
|
1460
|
-
- Analysis that might need course correction
|
|
1461
|
-
- Problems where the full scope might not be clear initially
|
|
1462
|
-
- Problems that require a multi-step solution
|
|
1463
|
-
- Tasks that need to maintain context over multiple steps
|
|
1464
|
-
- Situations where irrelevant information needs to be filtered out
|
|
1465
|
-
- When you need guidance on which tools to use and in what order
|
|
1466
|
-
- When you need guidance on which skills to invoke for specific workflows
|
|
857
|
+
When to use this tool:
|
|
858
|
+
- Breaking down complex problems into steps
|
|
859
|
+
- Planning and design with room for revision
|
|
860
|
+
- Analysis that might need course correction
|
|
861
|
+
- Problems where the full scope might not be clear initially
|
|
862
|
+
- Problems that require a multi-step solution
|
|
863
|
+
- Tasks that need to maintain context over multiple steps
|
|
864
|
+
- Situations where irrelevant information needs to be filtered out
|
|
865
|
+
- When you need guidance on which tools to use and in what order
|
|
866
|
+
- When you need guidance on which skills to invoke for specific workflows
|
|
1467
867
|
|
|
1468
868
|
Key features:
|
|
1469
869
|
- You can adjust total_thoughts up or down as you progress
|
|
@@ -1491,7 +891,7 @@ Parameters explained:
|
|
|
1491
891
|
* Hypothesis generation
|
|
1492
892
|
* Hypothesis verification
|
|
1493
893
|
* Tool recommendations and rationale
|
|
1494
|
-
- next_thought_needed: True if you need more thinking, even if at what seemed like the end
|
|
894
|
+
- next_thought_needed: True if you need more thinking, even if at what seemed like the end. Omission defaults to true; the effective next action is in strategy_hint.
|
|
1495
895
|
- thought_number: Current number in sequence (can go beyond initial total if needed)
|
|
1496
896
|
- total_thoughts: Current estimate of thoughts needed (can be adjusted up/down)
|
|
1497
897
|
- is_revision: A boolean indicating if this thought revises previous thinking
|
|
@@ -1785,7 +1185,7 @@ You should:
|
|
|
1785
1185
|
available_skills: valibot__rspack_import_0.optional(valibot__rspack_import_0.pipe(valibot__rspack_import_0.array(valibot__rspack_import_0.string()), valibot__rspack_import_0.description('Array of skill names available for use (e.g., ["commit", "review-pr", "pdf"])'))),
|
|
1786
1186
|
thought: valibot__rspack_import_0.pipe(valibot__rspack_import_0.string(), valibot__rspack_import_0.description('Your current thinking step')),
|
|
1787
1187
|
id: valibot__rspack_import_0.optional(valibot__rspack_import_0.pipe(valibot__rspack_import_0.string(), valibot__rspack_import_0.minLength(1), valibot__rspack_import_0.maxLength(30), valibot__rspack_import_0.description('Unique identifier for this thought. Auto-generated if not provided.'))),
|
|
1788
|
-
next_thought_needed: valibot__rspack_import_0.optional(valibot__rspack_import_0.pipe(valibot__rspack_import_0.boolean(), valibot__rspack_import_0.description('
|
|
1188
|
+
next_thought_needed: valibot__rspack_import_0.optional(valibot__rspack_import_0.pipe(valibot__rspack_import_0.boolean(), valibot__rspack_import_0.description('Omission defaults to true; the effective next action is returned in strategy_hint.'))),
|
|
1789
1189
|
thought_number: valibot__rspack_import_0.pipe(valibot__rspack_import_0.number(), valibot__rspack_import_0.minValue(1), valibot__rspack_import_0.description('Current thought number')),
|
|
1790
1190
|
total_thoughts: valibot__rspack_import_0.pipe(valibot__rspack_import_0.number(), valibot__rspack_import_0.minValue(1), valibot__rspack_import_0.description('Estimated total thoughts needed')),
|
|
1791
1191
|
is_revision: valibot__rspack_import_0.optional(valibot__rspack_import_0.pipe(valibot__rspack_import_0.boolean(), valibot__rspack_import_0.description('Whether this revises previous thinking'))),
|
|
@@ -1926,8 +1326,61 @@ __webpack_require__.d(__webpack_exports__, {
|
|
|
1926
1326
|
|
|
1927
1327
|
|
|
1928
1328
|
},
|
|
1929
|
-
"
|
|
1930
|
-
|
|
1329
|
+
"E"(__unused_rspack_module, __webpack_exports__, __webpack_require__) {
|
|
1330
|
+
|
|
1331
|
+
// EXPORTS
|
|
1332
|
+
__webpack_require__.d(__webpack_exports__, {
|
|
1333
|
+
StreamableHttpTransport: () => (/* binding */ StreamableHttpTransport)
|
|
1334
|
+
});
|
|
1335
|
+
|
|
1336
|
+
// UNUSED EXPORTS: createStreamableHttpTransport
|
|
1337
|
+
|
|
1338
|
+
;// CONCATENATED MODULE: external "node:crypto"
|
|
1339
|
+
|
|
1340
|
+
;// CONCATENATED MODULE: external "node:http"
|
|
1341
|
+
|
|
1342
|
+
// EXTERNAL MODULE: external "valibot"
|
|
1343
|
+
var external_valibot_ = __webpack_require__("w");
|
|
1344
|
+
// EXTERNAL MODULE: ./src/errors.ts
|
|
1345
|
+
var errors = __webpack_require__("U");
|
|
1346
|
+
// EXTERNAL MODULE: ./src/schema.ts
|
|
1347
|
+
var schema = __webpack_require__("R");
|
|
1348
|
+
;// CONCATENATED MODULE: ./src/core/ids.ts
|
|
1349
|
+
/**
|
|
1350
|
+
* Unique identifier generation utilities for thoughts and edges.
|
|
1351
|
+
*
|
|
1352
|
+
* @module core/ids
|
|
1353
|
+
*/
|
|
1354
|
+
/**
|
|
1355
|
+
* Generate a unique lexicographically-sortable identifier.
|
|
1356
|
+
*
|
|
1357
|
+
* Format: 8-char base36 timestamp + 20-char hex random (10 random bytes).
|
|
1358
|
+
* Result is up to 28 characters, sortable by creation time.
|
|
1359
|
+
*
|
|
1360
|
+
* @returns A unique string identifier.
|
|
1361
|
+
*
|
|
1362
|
+
* @example
|
|
1363
|
+
* ```typescript
|
|
1364
|
+
* const id = generateUlid(); // '01h2k3m400a1b2c3d4e5f6...'
|
|
1365
|
+
* ```
|
|
1366
|
+
*/ function ids_generateUlid() {
|
|
1367
|
+
const timestamp = Date.now().toString(36).padStart(8, '0');
|
|
1368
|
+
const random = crypto.randomBytes(10).toString('hex');
|
|
1369
|
+
return `${timestamp}${random}`;
|
|
1370
|
+
}
|
|
1371
|
+
/**
|
|
1372
|
+
* Valid session ID pattern: alphanumeric, hyphens, underscores.
|
|
1373
|
+
*
|
|
1374
|
+
* Length is enforced separately via {@link MAX_SESSION_ID_LENGTH}.
|
|
1375
|
+
* Same character set as branch IDs.
|
|
1376
|
+
*/ const SESSION_ID_PATTERN = /^[a-zA-Z0-9_-]+$/;
|
|
1377
|
+
/**
|
|
1378
|
+
* Maximum session ID length (in characters).
|
|
1379
|
+
*
|
|
1380
|
+
* Allows compound identifiers (e.g. `user-123_task-abc`).
|
|
1381
|
+
*/ const MAX_SESSION_ID_LENGTH = 100;
|
|
1382
|
+
|
|
1383
|
+
;// CONCATENATED MODULE: ./src/transport/BaseTransport.ts
|
|
1931
1384
|
/**
|
|
1932
1385
|
* Base transport implementation.
|
|
1933
1386
|
*
|
|
@@ -2018,7 +1471,7 @@ class BaseTransport {
|
|
|
2018
1471
|
if (sessionId.length > (/* inlined export .MAX_SESSION_ID_LENGTH */100)) {
|
|
2019
1472
|
return false;
|
|
2020
1473
|
}
|
|
2021
|
-
return
|
|
1474
|
+
return SESSION_ID_PATTERN.test(sessionId);
|
|
2022
1475
|
}
|
|
2023
1476
|
/**
|
|
2024
1477
|
* Sanitize query parameters by removing any not in whitelist.
|
|
@@ -2256,669 +1709,83 @@ class BaseTransport {
|
|
|
2256
1709
|
}
|
|
2257
1710
|
}
|
|
2258
1711
|
|
|
2259
|
-
|
|
2260
|
-
j: () => (BaseTransport)
|
|
2261
|
-
});
|
|
2262
|
-
|
|
2263
|
-
|
|
2264
|
-
},
|
|
2265
|
-
"W"(__unused_rspack_module, __webpack_exports__, __webpack_require__) {
|
|
2266
|
-
/* import */ var node_http__rspack_import_0 = __webpack_require__("S");
|
|
2267
|
-
/* import */ var node_crypto__rspack_import_1 = __webpack_require__("i");
|
|
2268
|
-
/* import */ var node_url__rspack_import_2 = __webpack_require__("Y");
|
|
2269
|
-
/* import */ var valibot__rspack_import_3 = __webpack_require__("w");
|
|
2270
|
-
/* import */ var _errors_js__rspack_import_4 = __webpack_require__("U");
|
|
2271
|
-
/* import */ var _pool_PoolErrors_js__rspack_import_5 = __webpack_require__("K");
|
|
2272
|
-
/* import */ var _schema_js__rspack_import_6 = __webpack_require__("R");
|
|
2273
|
-
/* import */ var _BaseTransport_js__rspack_import_7 = __webpack_require__("o");
|
|
2274
|
-
/* import */ var _contracts_ids_js__rspack_import_8 = __webpack_require__("j");
|
|
2275
|
-
/* import */ var _context_RequestContext_js__rspack_import_9 = __webpack_require__("y");
|
|
2276
|
-
/* import */ var _utils_js__rspack_import_10 = __webpack_require__("h");
|
|
1712
|
+
;// CONCATENATED MODULE: ./src/contracts/ids.ts
|
|
2277
1713
|
/**
|
|
2278
|
-
*
|
|
2279
|
-
*
|
|
2280
|
-
* This transport allows multiple concurrent connections over HTTP using Server-Sent Events,
|
|
2281
|
-
* enabling multi-user scenarios and horizontal scaling.
|
|
1714
|
+
* Branded identifier types for compile-time slot safety.
|
|
2282
1715
|
*
|
|
2283
|
-
*
|
|
2284
|
-
*
|
|
1716
|
+
* These nominal types prevent accidental mixing of different ID kinds
|
|
1717
|
+
* (e.g. passing a `ThoughtId` where a `SessionId` is expected). At
|
|
1718
|
+
* runtime they are plain strings — the brand exists only in the type
|
|
1719
|
+
* system.
|
|
2285
1720
|
*
|
|
2286
|
-
* @
|
|
2287
|
-
* ```typescript
|
|
2288
|
-
* const transport = new SseTransport({
|
|
2289
|
-
* port: 3000,
|
|
2290
|
-
* host: 'localhost'
|
|
2291
|
-
* });
|
|
2292
|
-
* await transport.connect(server);
|
|
2293
|
-
* ```
|
|
1721
|
+
* @module contracts/ids
|
|
2294
1722
|
*/
|
|
2295
1723
|
|
|
2296
|
-
|
|
2297
|
-
|
|
2298
|
-
|
|
2299
|
-
|
|
2300
|
-
|
|
2301
|
-
|
|
2302
|
-
|
|
2303
|
-
|
|
2304
|
-
|
|
2305
|
-
/** Rejects persistence backends that cannot isolate pooled SSE child servers. */ function assertPooledSsePersistence(poolingEnabled, persistence) {
|
|
2306
|
-
if (poolingEnabled && persistence?.enabled === true && (persistence.backend === 'file' || persistence.backend === 'sqlite')) {
|
|
2307
|
-
throw new _errors_js__rspack_import_4/* .ConfigurationError */.j1(`pooled SSE does not support ${persistence.backend} persistence`);
|
|
2308
|
-
}
|
|
2309
|
-
}
|
|
2310
1724
|
/**
|
|
2311
|
-
*
|
|
2312
|
-
*
|
|
2313
|
-
* This transport uses Server-Sent Events (SSE) to communicate with clients,
|
|
2314
|
-
* allowing multiple concurrent connections and web-based clients.
|
|
1725
|
+
* Validate and brand a string as a {@link SessionId}.
|
|
2315
1726
|
*
|
|
2316
|
-
* @
|
|
2317
|
-
*
|
|
2318
|
-
* - Session ID validation (alphanumeric, max 64 chars)
|
|
2319
|
-
* - Query parameter sanitization (whitelist allowed keys)
|
|
2320
|
-
* - Rate limiting per IP (configurable, default 100 req/min)
|
|
2321
|
-
* - CORS origin validation
|
|
1727
|
+
* Enforces {@link SESSION_ID_PATTERN} and {@link MAX_SESSION_ID_LENGTH}.
|
|
1728
|
+
* The reserved global session sentinel `__global__` is always accepted.
|
|
2322
1729
|
*
|
|
2323
|
-
*
|
|
2324
|
-
|
|
2325
|
-
|
|
2326
|
-
|
|
2327
|
-
|
|
2328
|
-
get kind() {
|
|
2329
|
-
return 'sse';
|
|
1730
|
+
* @throws {ValidationError} when the input is not a valid session id.
|
|
1731
|
+
*/ function asSessionId(value) {
|
|
1732
|
+
if (value === '__global__') {
|
|
1733
|
+
// eslint-disable-next-line no-restricted-syntax -- branding constructor, cannot self-reference
|
|
1734
|
+
return value;
|
|
2330
1735
|
}
|
|
2331
|
-
|
|
2332
|
-
|
|
2333
|
-
_clients = new Set();
|
|
2334
|
-
_clientSessionMap = new Map();
|
|
2335
|
-
_sessionAttachmentCounts = new Map();
|
|
2336
|
-
_releasePromises = new WeakMap();
|
|
2337
|
-
_pendingReleases = new Set();
|
|
2338
|
-
_releaseFailures = new Set();
|
|
2339
|
-
_messageQueue = new Map();
|
|
2340
|
-
_metrics;
|
|
2341
|
-
_connectionPool;
|
|
2342
|
-
_stopPromise = null;
|
|
2343
|
-
constructor(options = {}){
|
|
2344
|
-
assertPooledSsePersistence(options.connectionPool !== undefined, options.persistence);
|
|
2345
|
-
super(options);
|
|
2346
|
-
this._path = options.path ?? '/sse';
|
|
2347
|
-
this._metrics = options.metrics;
|
|
2348
|
-
this._connectionPool = options.connectionPool;
|
|
2349
|
-
this._updateActiveConnectionsMetric();
|
|
2350
|
-
this._server = (0,node_http__rspack_import_0.createServer)((req, res)=>this._handleRequest(req, res));
|
|
1736
|
+
if (typeof value !== 'string' || value.length === 0) {
|
|
1737
|
+
throw new errors/* .ValidationError */.yI('session_id', 'must be a non-empty string');
|
|
2351
1738
|
}
|
|
2352
|
-
|
|
2353
|
-
|
|
2354
|
-
*
|
|
2355
|
-
* @param mcpServer - The MCP server instance
|
|
2356
|
-
*/ async connect(mcpServer) {
|
|
2357
|
-
this._mcpServer = mcpServer;
|
|
2358
|
-
return new Promise((resolve, reject)=>{
|
|
2359
|
-
const cleanup = ()=>{
|
|
2360
|
-
this._server.off('error', onError);
|
|
2361
|
-
this._server.off('listening', onListening);
|
|
2362
|
-
};
|
|
2363
|
-
const onError = (error)=>{
|
|
2364
|
-
cleanup();
|
|
2365
|
-
reject(error);
|
|
2366
|
-
};
|
|
2367
|
-
const onListening = ()=>{
|
|
2368
|
-
cleanup();
|
|
2369
|
-
this.log('info', `SSE transport listening on http://${this._host}:${this._port}`);
|
|
2370
|
-
resolve();
|
|
2371
|
-
};
|
|
2372
|
-
this._server.once('error', onError);
|
|
2373
|
-
this._server.once('listening', onListening);
|
|
2374
|
-
try {
|
|
2375
|
-
this._server.listen(this._port, this._host);
|
|
2376
|
-
} catch (error) {
|
|
2377
|
-
cleanup();
|
|
2378
|
-
reject(error);
|
|
2379
|
-
}
|
|
2380
|
-
});
|
|
1739
|
+
if (value.length > (/* inlined export .MAX_SESSION_ID_LENGTH */100)) {
|
|
1740
|
+
throw new errors/* .ValidationError */.yI('session_id', `exceeds max length of ${(/* inlined export .MAX_SESSION_ID_LENGTH */100)}`);
|
|
2381
1741
|
}
|
|
2382
|
-
|
|
2383
|
-
|
|
2384
|
-
* Handle incoming HTTP requests
|
|
2385
|
-
*/ async _handleRequest(req, res) {
|
|
2386
|
-
const routing = this._prepareRequest(req, res);
|
|
2387
|
-
if (!routing) return;
|
|
2388
|
-
if (this._enableCors && req.method === 'OPTIONS') {
|
|
2389
|
-
res.writeHead(204);
|
|
2390
|
-
res.end();
|
|
2391
|
-
return;
|
|
2392
|
-
}
|
|
2393
|
-
if (routing.url.pathname === this._path && req.method === 'GET') {
|
|
2394
|
-
await this._handleSseConnection(req, res, routing.params);
|
|
2395
|
-
return;
|
|
2396
|
-
}
|
|
2397
|
-
if (routing.url.pathname === `${this._path}/message` && req.method === 'POST') {
|
|
2398
|
-
await this._handleMessage(req, res, routing.params);
|
|
2399
|
-
return;
|
|
2400
|
-
}
|
|
2401
|
-
if (routing.url.pathname === '/health') {
|
|
2402
|
-
this._handleHealthCheck(res);
|
|
2403
|
-
return;
|
|
2404
|
-
}
|
|
2405
|
-
if (routing.url.pathname === '/ready') {
|
|
2406
|
-
await this._handleReadinessCheck(res);
|
|
2407
|
-
return;
|
|
2408
|
-
}
|
|
2409
|
-
res.writeHead(404, {
|
|
2410
|
-
'Content-Type': 'text/plain'
|
|
2411
|
-
});
|
|
2412
|
-
res.end('Not Found');
|
|
2413
|
-
}
|
|
2414
|
-
_prepareRequest(req, res) {
|
|
2415
|
-
const startTime = Date.now();
|
|
2416
|
-
const requestPath = req.url || '/';
|
|
2417
|
-
const requestMethod = req.method || 'GET';
|
|
2418
|
-
this._metrics?.counter('http_requests_total', 1, {
|
|
2419
|
-
transport: 'sse',
|
|
2420
|
-
method: requestMethod,
|
|
2421
|
-
path: requestPath
|
|
2422
|
-
}, 'Total HTTP requests');
|
|
2423
|
-
res.once('finish', ()=>{
|
|
2424
|
-
const durationSeconds = (Date.now() - startTime) / 1000;
|
|
2425
|
-
this._metrics?.histogram('http_request_duration_seconds', durationSeconds, {
|
|
2426
|
-
transport: 'sse',
|
|
2427
|
-
path: requestPath
|
|
2428
|
-
});
|
|
2429
|
-
});
|
|
2430
|
-
if (!this.validateHostHeader(req)) {
|
|
2431
|
-
this._metrics?.counter('http_request_errors_total', 1, {
|
|
2432
|
-
transport: 'sse',
|
|
2433
|
-
error_type: 'forbidden'
|
|
2434
|
-
}, 'Total HTTP request errors');
|
|
2435
|
-
res.writeHead(403, {
|
|
2436
|
-
'Content-Type': 'application/json'
|
|
2437
|
-
});
|
|
2438
|
-
res.end(JSON.stringify({
|
|
2439
|
-
error: 'Forbidden - invalid host header'
|
|
2440
|
-
}));
|
|
2441
|
-
return;
|
|
2442
|
-
}
|
|
2443
|
-
const url = new node_url__rspack_import_2.URL(req.url || '', `http://${req.headers.host}`);
|
|
2444
|
-
// Check rate limit first
|
|
2445
|
-
const clientIp = this.getClientIp(req);
|
|
2446
|
-
if (this.checkRateLimit(clientIp)) {
|
|
2447
|
-
this._metrics?.counter('http_request_errors_total', 1, {
|
|
2448
|
-
transport: 'sse',
|
|
2449
|
-
error_type: 'rate_limit'
|
|
2450
|
-
}, 'Total HTTP request errors');
|
|
2451
|
-
res.writeHead(429, {
|
|
2452
|
-
'Content-Type': 'application/json',
|
|
2453
|
-
'Retry-After': '60'
|
|
2454
|
-
});
|
|
2455
|
-
res.end(JSON.stringify({
|
|
2456
|
-
error: 'Too many requests'
|
|
2457
|
-
}));
|
|
2458
|
-
return;
|
|
2459
|
-
}
|
|
2460
|
-
// Validate CORS origin
|
|
2461
|
-
if (!this.validateCorsOrigin(req)) {
|
|
2462
|
-
this._metrics?.counter('http_request_errors_total', 1, {
|
|
2463
|
-
transport: 'sse',
|
|
2464
|
-
error_type: 'forbidden'
|
|
2465
|
-
}, 'Total HTTP request errors');
|
|
2466
|
-
res.writeHead(403, {
|
|
2467
|
-
'Content-Type': 'application/json'
|
|
2468
|
-
});
|
|
2469
|
-
res.end(JSON.stringify({
|
|
2470
|
-
error: 'Forbidden - invalid origin'
|
|
2471
|
-
}));
|
|
2472
|
-
return;
|
|
2473
|
-
}
|
|
2474
|
-
// Set CORS headers
|
|
2475
|
-
this.setCorsHeaders(res);
|
|
2476
|
-
// Sanitize query parameters
|
|
2477
|
-
const sanitizedParams = this.sanitizeQueryParams(url);
|
|
2478
|
-
// Validate session ID if present
|
|
2479
|
-
const requestSessionId = sanitizedParams.session ?? sanitizedParams.sessionId;
|
|
2480
|
-
if (requestSessionId !== undefined && !this.validateSessionId(requestSessionId)) {
|
|
2481
|
-
this._metrics?.counter('http_request_errors_total', 1, {
|
|
2482
|
-
transport: 'sse',
|
|
2483
|
-
error_type: 'validation'
|
|
2484
|
-
}, 'Total HTTP request errors');
|
|
2485
|
-
res.writeHead(400, {
|
|
2486
|
-
'Content-Type': 'application/json'
|
|
2487
|
-
});
|
|
2488
|
-
res.end(JSON.stringify({
|
|
2489
|
-
error: 'Invalid session ID format'
|
|
2490
|
-
}));
|
|
2491
|
-
return undefined;
|
|
2492
|
-
}
|
|
2493
|
-
return {
|
|
2494
|
-
url,
|
|
2495
|
-
params: sanitizedParams
|
|
2496
|
-
};
|
|
2497
|
-
}
|
|
2498
|
-
/**
|
|
2499
|
-
* Handle health check (liveness) endpoint
|
|
2500
|
-
*/ _handleHealthCheck(res) {
|
|
2501
|
-
const healthData = {
|
|
2502
|
-
status: 'healthy',
|
|
2503
|
-
clients: this._clients.size
|
|
2504
|
-
};
|
|
2505
|
-
if (this._connectionPool) {
|
|
2506
|
-
const poolStats = this._connectionPool.getStats();
|
|
2507
|
-
healthData.pool = poolStats;
|
|
2508
|
-
}
|
|
2509
|
-
if (this._healthChecker) {
|
|
2510
|
-
const liveness = this._healthChecker.checkLiveness();
|
|
2511
|
-
healthData.liveness = liveness;
|
|
2512
|
-
}
|
|
2513
|
-
res.writeHead(200, {
|
|
2514
|
-
'Content-Type': 'application/json'
|
|
2515
|
-
});
|
|
2516
|
-
res.end(JSON.stringify(healthData));
|
|
2517
|
-
}
|
|
2518
|
-
/**
|
|
2519
|
-
* Handle readiness check endpoint
|
|
2520
|
-
*/ async _handleReadinessCheck(res) {
|
|
2521
|
-
if (this._healthChecker) {
|
|
2522
|
-
const readiness = await this._healthChecker.checkReadiness();
|
|
2523
|
-
const statusCode = readiness.status === 'ok' ? 200 : 503;
|
|
2524
|
-
res.writeHead(statusCode, {
|
|
2525
|
-
'Content-Type': 'application/json'
|
|
2526
|
-
});
|
|
2527
|
-
res.end(JSON.stringify(readiness));
|
|
2528
|
-
} else {
|
|
2529
|
-
res.writeHead(200, {
|
|
2530
|
-
'Content-Type': 'application/json'
|
|
2531
|
-
});
|
|
2532
|
-
res.end(JSON.stringify({
|
|
2533
|
-
status: 'ok',
|
|
2534
|
-
timestamp: new Date().toISOString(),
|
|
2535
|
-
components: {}
|
|
2536
|
-
}));
|
|
2537
|
-
}
|
|
2538
|
-
}
|
|
2539
|
-
/**
|
|
2540
|
-
* Handle new SSE connection
|
|
2541
|
-
*/ async _handleSseConnection(req, res, params) {
|
|
2542
|
-
// Set SSE headers
|
|
2543
|
-
res.writeHead(200, {
|
|
2544
|
-
'Content-Type': 'text/event-stream',
|
|
2545
|
-
'Cache-Control': 'no-cache',
|
|
2546
|
-
Connection: 'keep-alive'
|
|
2547
|
-
});
|
|
2548
|
-
// Resolve session ID when pool is active
|
|
2549
|
-
let sessionId;
|
|
2550
|
-
if (this._connectionPool) {
|
|
2551
|
-
const requestedSession = params.session ?? params.sessionId;
|
|
2552
|
-
const requestedSessionId = requestedSession ? (0,_contracts_ids_js__rspack_import_8/* .asSessionId */.Kd)(requestedSession) : undefined;
|
|
2553
|
-
if (requestedSessionId && this._connectionPool.getSessionInfo(requestedSessionId)) {
|
|
2554
|
-
sessionId = requestedSessionId;
|
|
2555
|
-
} else {
|
|
2556
|
-
try {
|
|
2557
|
-
sessionId = await this._connectionPool.createSession();
|
|
2558
|
-
} catch (error) {
|
|
2559
|
-
res.write(`event: error\n`);
|
|
2560
|
-
res.write(`data: ${JSON.stringify({
|
|
2561
|
-
error: error instanceof Error ? error.message : 'Failed to create session'
|
|
2562
|
-
})}\n\n`);
|
|
2563
|
-
res.end();
|
|
2564
|
-
return;
|
|
2565
|
-
}
|
|
2566
|
-
}
|
|
2567
|
-
this._clientSessionMap.set(res, sessionId);
|
|
2568
|
-
this._sessionAttachmentCounts.set(sessionId, (this._sessionAttachmentCounts.get(sessionId) ?? 0) + 1);
|
|
2569
|
-
this._updatePoolMetrics();
|
|
2570
|
-
}
|
|
2571
|
-
this._clients.add(res);
|
|
2572
|
-
this._updateActiveConnectionsMetric();
|
|
2573
|
-
const release = ()=>this._releaseAfterDisconnect(res);
|
|
2574
|
-
req.once('close', release);
|
|
2575
|
-
res.once('close', release);
|
|
2576
|
-
res.once('error', release);
|
|
2577
|
-
// Send initial connection event
|
|
2578
|
-
const connectedPayload = {
|
|
2579
|
-
timestamp: Date.now()
|
|
2580
|
-
};
|
|
2581
|
-
if (sessionId) {
|
|
2582
|
-
connectedPayload.sessionId = sessionId;
|
|
2583
|
-
}
|
|
2584
|
-
this._sendSseEvent(res, 'connected', connectedPayload);
|
|
2585
|
-
// Send any queued messages
|
|
2586
|
-
const clientId = this._generateClientId();
|
|
2587
|
-
const queued = this._messageQueue.get(clientId);
|
|
2588
|
-
if (queued) {
|
|
2589
|
-
for (const message of queued){
|
|
2590
|
-
this._sendSseEvent(res, 'message', message);
|
|
2591
|
-
}
|
|
2592
|
-
this._messageQueue.delete(clientId);
|
|
2593
|
-
}
|
|
2594
|
-
}
|
|
2595
|
-
/**
|
|
2596
|
-
* Handle incoming message from client
|
|
2597
|
-
*/ async _handleMessage(req, res, params) {
|
|
2598
|
-
let pooledOwner;
|
|
2599
|
-
if (this._connectionPool) {
|
|
2600
|
-
const correlation = params.session ?? params.sessionId;
|
|
2601
|
-
if (correlation === undefined) {
|
|
2602
|
-
res.writeHead(400, {
|
|
2603
|
-
'Content-Type': 'application/json'
|
|
2604
|
-
});
|
|
2605
|
-
res.end(JSON.stringify({
|
|
2606
|
-
error: 'Missing session ID'
|
|
2607
|
-
}));
|
|
2608
|
-
return;
|
|
2609
|
-
}
|
|
2610
|
-
pooledOwner = (0,_contracts_ids_js__rspack_import_8/* .asSessionId */.Kd)(correlation);
|
|
2611
|
-
}
|
|
2612
|
-
const jsonRpcRequest = await this._parseMessage(req, res);
|
|
2613
|
-
if (!jsonRpcRequest) return;
|
|
2614
|
-
const mcpServer = this._mcpServer;
|
|
2615
|
-
if (!mcpServer) {
|
|
2616
|
-
this._metrics?.counter('http_request_errors_total', 1, {
|
|
2617
|
-
transport: 'sse',
|
|
2618
|
-
error_type: 'server_not_ready'
|
|
2619
|
-
}, 'Total HTTP request errors');
|
|
2620
|
-
res.writeHead(503, {
|
|
2621
|
-
'Content-Type': 'application/json'
|
|
2622
|
-
});
|
|
2623
|
-
res.end(JSON.stringify({
|
|
2624
|
-
error: 'Server not ready'
|
|
2625
|
-
}));
|
|
2626
|
-
return;
|
|
2627
|
-
}
|
|
2628
|
-
const owner = pooledOwner ?? `sse-${(0,node_crypto__rspack_import_1.randomUUID)()}`;
|
|
2629
|
-
const receive = ()=>(0,_context_RequestContext_js__rspack_import_9/* .runWithContext */.Vo)({
|
|
2630
|
-
requestId: (0,node_crypto__rspack_import_1.randomUUID)(),
|
|
2631
|
-
owner
|
|
2632
|
-
}, ()=>mcpServer.receive(jsonRpcRequest, {
|
|
2633
|
-
sessionInfo: {}
|
|
2634
|
-
}));
|
|
2635
|
-
try {
|
|
2636
|
-
let response;
|
|
2637
|
-
if (this._connectionPool && pooledOwner) {
|
|
2638
|
-
if (typeof this._connectionPool.runWithSession !== 'function') {
|
|
2639
|
-
this._writeSessionUnavailable(res);
|
|
2640
|
-
return;
|
|
2641
|
-
}
|
|
2642
|
-
const result = await this._connectionPool.runWithSession(pooledOwner, receive);
|
|
2643
|
-
switch(result.status){
|
|
2644
|
-
case 'completed':
|
|
2645
|
-
response = result.value;
|
|
2646
|
-
break;
|
|
2647
|
-
case 'inactive':
|
|
2648
|
-
case 'missing':
|
|
2649
|
-
this._writeSessionUnavailable(res);
|
|
2650
|
-
return;
|
|
2651
|
-
default:
|
|
2652
|
-
return (0,_utils_js__rspack_import_10/* .assertNever */.x)(result);
|
|
2653
|
-
}
|
|
2654
|
-
} else {
|
|
2655
|
-
response = await receive();
|
|
2656
|
-
}
|
|
2657
|
-
res.writeHead(200, {
|
|
2658
|
-
'Content-Type': 'application/json'
|
|
2659
|
-
});
|
|
2660
|
-
res.end(JSON.stringify(response ?? {
|
|
2661
|
-
jsonrpc: '2.0',
|
|
2662
|
-
id: 'id' in jsonRpcRequest ? jsonRpcRequest.id : null,
|
|
2663
|
-
result: null
|
|
2664
|
-
}));
|
|
2665
|
-
} catch (error) {
|
|
2666
|
-
if (error instanceof _pool_PoolErrors_js__rspack_import_5/* .SessionNotFoundError */.A || error instanceof _pool_PoolErrors_js__rspack_import_5/* .SessionNotActiveError */.q) {
|
|
2667
|
-
this._writeSessionUnavailable(res);
|
|
2668
|
-
return;
|
|
2669
|
-
}
|
|
2670
|
-
throw error;
|
|
2671
|
-
}
|
|
2672
|
-
}
|
|
2673
|
-
async _parseMessage(req, res) {
|
|
2674
|
-
let body = '';
|
|
2675
|
-
for await (const chunk of req){
|
|
2676
|
-
body += chunk.toString();
|
|
2677
|
-
}
|
|
2678
|
-
let rawBody;
|
|
2679
|
-
try {
|
|
2680
|
-
rawBody = JSON.parse(body);
|
|
2681
|
-
} catch (error) {
|
|
2682
|
-
if (!(error instanceof SyntaxError)) throw error;
|
|
2683
|
-
this._metrics?.counter('http_request_errors_total', 1, {
|
|
2684
|
-
transport: 'sse',
|
|
2685
|
-
error_type: 'parse_error'
|
|
2686
|
-
}, 'Total HTTP request errors');
|
|
2687
|
-
res.writeHead(400, {
|
|
2688
|
-
'Content-Type': 'application/json'
|
|
2689
|
-
});
|
|
2690
|
-
res.end(JSON.stringify({
|
|
2691
|
-
error: 'Invalid JSON'
|
|
2692
|
-
}));
|
|
2693
|
-
return;
|
|
2694
|
-
}
|
|
2695
|
-
const parseResult = (0,valibot__rspack_import_3.safeParse)(_schema_js__rspack_import_6/* .JsonRpcRequestSchema */.Uv, rawBody);
|
|
2696
|
-
const rawId = rawBody && typeof rawBody === 'object' && 'id' in rawBody ? rawBody.id ?? null : null;
|
|
2697
|
-
if (!parseResult.success) {
|
|
2698
|
-
this._metrics?.counter('http_request_errors_total', 1, {
|
|
2699
|
-
transport: 'sse',
|
|
2700
|
-
error_type: 'validation'
|
|
2701
|
-
}, 'Total HTTP request errors');
|
|
2702
|
-
res.writeHead(200, {
|
|
2703
|
-
'Content-Type': 'application/json'
|
|
2704
|
-
});
|
|
2705
|
-
res.end(JSON.stringify({
|
|
2706
|
-
jsonrpc: '2.0',
|
|
2707
|
-
id: rawId,
|
|
2708
|
-
error: {
|
|
2709
|
-
code: -32600,
|
|
2710
|
-
message: 'Invalid Request',
|
|
2711
|
-
data: parseResult.issues
|
|
2712
|
-
}
|
|
2713
|
-
}));
|
|
2714
|
-
return;
|
|
2715
|
-
}
|
|
2716
|
-
return parseResult.output;
|
|
2717
|
-
}
|
|
2718
|
-
_writeSessionUnavailable(res) {
|
|
2719
|
-
res.writeHead(404, {
|
|
2720
|
-
'Content-Type': 'application/json'
|
|
2721
|
-
});
|
|
2722
|
-
res.end(JSON.stringify({
|
|
2723
|
-
error: 'Session not found'
|
|
2724
|
-
}));
|
|
2725
|
-
}
|
|
2726
|
-
_releaseClient(res) {
|
|
2727
|
-
const existing = this._releasePromises.get(res);
|
|
2728
|
-
if (existing) {
|
|
2729
|
-
return existing;
|
|
2730
|
-
}
|
|
2731
|
-
this._clients.delete(res);
|
|
2732
|
-
const sessionId = this._clientSessionMap.get(res);
|
|
2733
|
-
this._clientSessionMap.delete(res);
|
|
2734
|
-
this._updateActiveConnectionsMetric();
|
|
2735
|
-
let releasePromise = Promise.resolve();
|
|
2736
|
-
if (sessionId && this._connectionPool) {
|
|
2737
|
-
const attachmentCount = this._sessionAttachmentCounts.get(sessionId);
|
|
2738
|
-
if (attachmentCount !== undefined && attachmentCount > 1) {
|
|
2739
|
-
this._sessionAttachmentCounts.set(sessionId, attachmentCount - 1);
|
|
2740
|
-
} else {
|
|
2741
|
-
this._sessionAttachmentCounts.delete(sessionId);
|
|
2742
|
-
releasePromise = this._connectionPool.closeSession(sessionId).catch((error)=>{
|
|
2743
|
-
if (error instanceof _pool_PoolErrors_js__rspack_import_5/* .SessionNotFoundError */.A) {
|
|
2744
|
-
return;
|
|
2745
|
-
}
|
|
2746
|
-
throw error;
|
|
2747
|
-
});
|
|
2748
|
-
}
|
|
2749
|
-
this._updatePoolMetrics();
|
|
2750
|
-
}
|
|
2751
|
-
this._releasePromises.set(res, releasePromise);
|
|
2752
|
-
this._pendingReleases.add(releasePromise);
|
|
2753
|
-
void releasePromise.then(()=>this._pendingReleases.delete(releasePromise), (error)=>{
|
|
2754
|
-
this._pendingReleases.delete(releasePromise);
|
|
2755
|
-
this._releaseFailures.add(error);
|
|
2756
|
-
});
|
|
2757
|
-
return releasePromise;
|
|
2758
|
-
}
|
|
2759
|
-
_releaseAfterDisconnect(res) {
|
|
2760
|
-
void this._releaseClient(res).catch((error)=>{
|
|
2761
|
-
this.log('error', 'SSE pooled session release failed', {
|
|
2762
|
-
error
|
|
2763
|
-
});
|
|
2764
|
-
});
|
|
2765
|
-
}
|
|
2766
|
-
/**
|
|
2767
|
-
* Send an SSE event to a specific client
|
|
2768
|
-
*/ _sendSseEvent(res, event, data) {
|
|
2769
|
-
try {
|
|
2770
|
-
res.write(`event: ${event}\n`);
|
|
2771
|
-
res.write(`data: ${JSON.stringify(data)}\n\n`);
|
|
2772
|
-
} catch {
|
|
2773
|
-
this._releaseAfterDisconnect(res);
|
|
2774
|
-
}
|
|
2775
|
-
}
|
|
2776
|
-
_updateActiveConnectionsMetric() {
|
|
2777
|
-
this._metrics?.gauge('sse_active_connections', this._clients.size, {}, 'Current active SSE connections');
|
|
2778
|
-
}
|
|
2779
|
-
_updatePoolMetrics() {
|
|
2780
|
-
if (!this._connectionPool || !this._metrics) {
|
|
2781
|
-
return;
|
|
2782
|
-
}
|
|
2783
|
-
const stats = this._connectionPool.getStats();
|
|
2784
|
-
this._metrics.gauge('sse_pool_active_sessions', stats.activeSessions, {}, 'Active sessions in connection pool');
|
|
2785
|
-
this._metrics.gauge('sse_pool_total_sessions', stats.totalSessions, {}, 'Total sessions in connection pool');
|
|
2786
|
-
this._metrics.gauge('sse_pool_max_sessions', stats.maxSessions, {}, 'Maximum sessions in connection pool');
|
|
2787
|
-
}
|
|
2788
|
-
/**
|
|
2789
|
-
* Broadcast a message to all connected clients
|
|
2790
|
-
*/ broadcast(event, data) {
|
|
2791
|
-
for (const client of this._clients){
|
|
2792
|
-
this._sendSseEvent(client, event, data);
|
|
2793
|
-
}
|
|
2794
|
-
}
|
|
2795
|
-
/**
|
|
2796
|
-
* Generate a unique client ID
|
|
2797
|
-
*/ _generateClientId() {
|
|
2798
|
-
return `client_${Date.now()}_${Math.random().toString(36).substring(2, 11)}`;
|
|
2799
|
-
}
|
|
2800
|
-
/**
|
|
2801
|
-
* Get number of connected clients
|
|
2802
|
-
*/ get clientCount() {
|
|
2803
|
-
return this._clients.size;
|
|
2804
|
-
}
|
|
2805
|
-
/**
|
|
2806
|
-
* Get the connection pool, if one was configured.
|
|
2807
|
-
*/ get connectionPool() {
|
|
2808
|
-
return this._connectionPool;
|
|
2809
|
-
}
|
|
2810
|
-
/**
|
|
2811
|
-
* Stop the transport server with graceful shutdown.
|
|
2812
|
-
*
|
|
2813
|
-
* @param timeout - Maximum time to wait for requests to drain (not used for SSE)
|
|
2814
|
-
* @returns Promise that resolves when shutdown is complete
|
|
2815
|
-
*/ stop(_timeout) {
|
|
2816
|
-
if (this._stopPromise) {
|
|
2817
|
-
return this._stopPromise;
|
|
2818
|
-
}
|
|
2819
|
-
const completion = Promise.withResolvers();
|
|
2820
|
-
this._stopPromise = completion.promise;
|
|
2821
|
-
this._isShuttingDown = true;
|
|
2822
|
-
this._stopRateLimitCleanup();
|
|
2823
|
-
const operations = new Set();
|
|
2824
|
-
for (const client of Array.from(this._clients)){
|
|
2825
|
-
operations.add(this._releaseClient(client));
|
|
2826
|
-
try {
|
|
2827
|
-
client.end();
|
|
2828
|
-
} catch (error) {
|
|
2829
|
-
operations.add(Promise.reject(error instanceof Error ? error : new AggregateError([
|
|
2830
|
-
error
|
|
2831
|
-
], 'SSE client close failed')));
|
|
2832
|
-
}
|
|
2833
|
-
}
|
|
2834
|
-
for (const release of this._pendingReleases){
|
|
2835
|
-
operations.add(release);
|
|
2836
|
-
}
|
|
2837
|
-
if (this._connectionPool) {
|
|
2838
|
-
operations.add(this._connectionPool.terminate());
|
|
2839
|
-
}
|
|
2840
|
-
operations.add(this._server.listening ? new Promise((resolve, reject)=>{
|
|
2841
|
-
this._server.close((error)=>error ? reject(error) : resolve());
|
|
2842
|
-
}) : Promise.resolve());
|
|
2843
|
-
void Promise.allSettled(operations).then((outcomes)=>{
|
|
2844
|
-
const failures = new Set(this._releaseFailures);
|
|
2845
|
-
for (const outcome of outcomes){
|
|
2846
|
-
if (outcome.status !== 'rejected') {
|
|
2847
|
-
continue;
|
|
2848
|
-
}
|
|
2849
|
-
if (outcome.reason instanceof AggregateError) {
|
|
2850
|
-
for (const error of outcome.reason.errors)failures.add(error);
|
|
2851
|
-
} else {
|
|
2852
|
-
failures.add(outcome.reason);
|
|
2853
|
-
}
|
|
2854
|
-
}
|
|
2855
|
-
this._clients.clear();
|
|
2856
|
-
this._clientSessionMap.clear();
|
|
2857
|
-
this._sessionAttachmentCounts.clear();
|
|
2858
|
-
this._updateActiveConnectionsMetric();
|
|
2859
|
-
this._updatePoolMetrics();
|
|
2860
|
-
if (failures.size > 0) {
|
|
2861
|
-
completion.reject(new AggregateError(failures, 'SSE transport shutdown failed'));
|
|
2862
|
-
return;
|
|
2863
|
-
}
|
|
2864
|
-
this.log('info', 'SSE transport stopped');
|
|
2865
|
-
completion.resolve();
|
|
2866
|
-
});
|
|
2867
|
-
return completion.promise;
|
|
1742
|
+
if (!SESSION_ID_PATTERN.test(value)) {
|
|
1743
|
+
throw new errors/* .ValidationError */.yI('session_id', 'must match alphanumeric, hyphens, underscores');
|
|
2868
1744
|
}
|
|
1745
|
+
// eslint-disable-next-line no-restricted-syntax -- branding constructor, cannot self-reference
|
|
1746
|
+
return value;
|
|
1747
|
+
}
|
|
1748
|
+
/** Brand a string as a {@link ThoughtId} without validation. */ function asThoughtId(value) {
|
|
1749
|
+
return value;
|
|
1750
|
+
}
|
|
1751
|
+
/** Brand a string as an {@link EdgeId} without validation. */ function asEdgeId(value) {
|
|
1752
|
+
return value;
|
|
1753
|
+
}
|
|
1754
|
+
/** Brand a string as a {@link SuspensionToken} without validation. */ function asSuspensionToken(value) {
|
|
1755
|
+
return value;
|
|
1756
|
+
}
|
|
1757
|
+
/** Brand a string as a {@link BranchId} without validation. */ function asBranchId(value) {
|
|
1758
|
+
return value;
|
|
1759
|
+
}
|
|
1760
|
+
/** Brand a string as a {@link SummaryId} without validation. */ function asSummaryId(value) {
|
|
1761
|
+
return value;
|
|
1762
|
+
}
|
|
1763
|
+
/** Generate a fresh {@link ThoughtId}. */ function generateThoughtId() {
|
|
1764
|
+
return generateUlid();
|
|
1765
|
+
}
|
|
1766
|
+
/** Generate a fresh {@link EdgeId}. */ function generateEdgeId() {
|
|
1767
|
+
return generateUlid();
|
|
1768
|
+
}
|
|
1769
|
+
/** Generate a fresh {@link SuspensionToken}. */ function generateSuspensionToken() {
|
|
1770
|
+
return generateUlid();
|
|
1771
|
+
}
|
|
1772
|
+
/** Generate a fresh {@link SummaryId}. */ function generateSummaryId() {
|
|
1773
|
+
return generateUlid();
|
|
2869
1774
|
}
|
|
2870
1775
|
/**
|
|
2871
|
-
*
|
|
2872
|
-
*
|
|
2873
|
-
* @param options - Transport configuration
|
|
2874
|
-
* @returns A configured SSE transport
|
|
1776
|
+
* Reserved sentinel session id used when callers omit `session_id`.
|
|
2875
1777
|
*
|
|
2876
|
-
*
|
|
2877
|
-
*
|
|
2878
|
-
|
|
2879
|
-
* await transport.connect(mcpServer);
|
|
2880
|
-
* ```
|
|
2881
|
-
*/ function createSseTransport(options = {}) {
|
|
2882
|
-
return new SseTransport(options);
|
|
2883
|
-
}
|
|
2884
|
-
|
|
2885
|
-
__webpack_require__.d(__webpack_exports__, {
|
|
2886
|
-
SseTransport: () => (SseTransport),
|
|
2887
|
-
c: () => (assertPooledSsePersistence)
|
|
2888
|
-
});
|
|
2889
|
-
|
|
2890
|
-
|
|
2891
|
-
},
|
|
2892
|
-
"J"(__unused_rspack_module, __webpack_exports__, __webpack_require__) {
|
|
2893
|
-
|
|
2894
|
-
// EXPORTS
|
|
2895
|
-
__webpack_require__.d(__webpack_exports__, {
|
|
2896
|
-
StreamableHttpTransport: () => (/* binding */ StreamableHttpTransport)
|
|
2897
|
-
});
|
|
2898
|
-
|
|
2899
|
-
// UNUSED EXPORTS: createStreamableHttpTransport
|
|
1778
|
+
* Branded once here so production and test code share one constant
|
|
1779
|
+
* instead of casting `'__global__'` ad-hoc.
|
|
1780
|
+
*/ const GLOBAL_SESSION_ID = asSessionId('__global__');
|
|
2900
1781
|
|
|
2901
|
-
// EXTERNAL MODULE: external "node:crypto"
|
|
2902
|
-
var external_node_crypto_ = __webpack_require__("i");
|
|
2903
|
-
// EXTERNAL MODULE: external "node:http"
|
|
2904
|
-
var external_node_http_ = __webpack_require__("S");
|
|
2905
|
-
// EXTERNAL MODULE: external "valibot"
|
|
2906
|
-
var external_valibot_ = __webpack_require__("w");
|
|
2907
|
-
// EXTERNAL MODULE: ./src/errors.ts
|
|
2908
|
-
var errors = __webpack_require__("U");
|
|
2909
|
-
// EXTERNAL MODULE: ./src/schema.ts
|
|
2910
|
-
var schema = __webpack_require__("R");
|
|
2911
|
-
// EXTERNAL MODULE: ./src/transport/BaseTransport.ts
|
|
2912
|
-
var BaseTransport = __webpack_require__("o");
|
|
2913
|
-
// EXTERNAL MODULE: ./src/contracts/ids.ts
|
|
2914
|
-
var ids = __webpack_require__("j");
|
|
2915
1782
|
;// CONCATENATED MODULE: ./src/transport/HttpHelpers.ts
|
|
2916
1783
|
/**
|
|
2917
1784
|
* Shared HTTP helper utilities for MCP transport implementations.
|
|
2918
1785
|
*
|
|
2919
1786
|
* Centralizes JSON-RPC response formatting, request body reading,
|
|
2920
1787
|
* and common HTTP response patterns to eliminate duplication across
|
|
2921
|
-
* HttpTransport
|
|
1788
|
+
* HttpTransport and StreamableHttpTransport.
|
|
2922
1789
|
*
|
|
2923
1790
|
* @module transport/HttpHelpers
|
|
2924
1791
|
*/ /**
|
|
@@ -3003,8 +1870,8 @@ var ids = __webpack_require__("j");
|
|
|
3003
1870
|
return body;
|
|
3004
1871
|
}
|
|
3005
1872
|
|
|
3006
|
-
// EXTERNAL MODULE: ./src/context/RequestContext.ts
|
|
3007
|
-
var RequestContext = __webpack_require__("
|
|
1873
|
+
// EXTERNAL MODULE: ./src/context/RequestContext.ts + 1 modules
|
|
1874
|
+
var RequestContext = __webpack_require__("i");
|
|
3008
1875
|
;// CONCATENATED MODULE: ./src/transport/HttpRequestLifecycle.ts
|
|
3009
1876
|
/** Maximum number of reporting failures retained for diagnostics. */ const LIFECYCLE_REPORTING_FAILURE_CAPACITY = 32;
|
|
3010
1877
|
class LifecycleFailureReporter {
|
|
@@ -3160,7 +2027,7 @@ class AcceptedWorkTracker {
|
|
|
3160
2027
|
* - 429: Too Many Requests
|
|
3161
2028
|
* - 500: Internal Server Error
|
|
3162
2029
|
* - 503: Server Not Ready / Shutting Down
|
|
3163
|
-
*/ class StreamableHttpTransport extends BaseTransport
|
|
2030
|
+
*/ class StreamableHttpTransport extends BaseTransport {
|
|
3164
2031
|
get kind() {
|
|
3165
2032
|
return 'streamable-http';
|
|
3166
2033
|
}
|
|
@@ -3184,7 +2051,7 @@ class AcceptedWorkTracker {
|
|
|
3184
2051
|
super(options);
|
|
3185
2052
|
this._path = options.path ?? '/mcp';
|
|
3186
2053
|
this._stateful = options.stateful ?? true;
|
|
3187
|
-
this._sessionIdGenerator = options.sessionIdGenerator ?? (()=>(0,
|
|
2054
|
+
this._sessionIdGenerator = options.sessionIdGenerator ?? (()=>(0,__rspack_external_node_crypto_2e7c4b46.randomUUID)());
|
|
3188
2055
|
this._bodySizeLimitEnabled = options.enableBodySizeLimit ?? true;
|
|
3189
2056
|
this._maxBodySize = options.maxBodySize ?? 10 * 1024 * 1024;
|
|
3190
2057
|
this._requestTimeout = options.requestTimeout ?? 30000;
|
|
@@ -3217,7 +2084,7 @@ class AcceptedWorkTracker {
|
|
|
3217
2084
|
* Connects MCP server to this transport and starts listening.
|
|
3218
2085
|
*/ async connect(mcpServer) {
|
|
3219
2086
|
this._mcpServer = mcpServer;
|
|
3220
|
-
const server = (0,
|
|
2087
|
+
const server = (0,__rspack_external_node_http_e245b239.createServer)((req, res)=>{
|
|
3221
2088
|
const responseFinalizer = new ResponseFinalizer(res, this._lifecycleFailureReporter);
|
|
3222
2089
|
void this._handleRequest(req, res).catch((error)=>{
|
|
3223
2090
|
this._lifecycleFailureReporter.report(error);
|
|
@@ -3435,9 +2302,9 @@ class AcceptedWorkTracker {
|
|
|
3435
2302
|
}
|
|
3436
2303
|
}
|
|
3437
2304
|
async _receiveAndFinalize(jsonRpcRequest, sessionId, responseFinalizer) {
|
|
3438
|
-
const owner = this._stateful ? sessionId ?? (0,
|
|
2305
|
+
const owner = this._stateful ? sessionId ?? (0,__rspack_external_node_crypto_2e7c4b46.randomUUID)() : (0,__rspack_external_node_crypto_2e7c4b46.randomUUID)();
|
|
3439
2306
|
const response = await (0,RequestContext/* .runWithContext */.Vo)({
|
|
3440
|
-
requestId: (0,
|
|
2307
|
+
requestId: (0,__rspack_external_node_crypto_2e7c4b46.randomUUID)(),
|
|
3441
2308
|
owner
|
|
3442
2309
|
}, ()=>this._requireMcpServer().receive(jsonRpcRequest, {
|
|
3443
2310
|
sessionInfo: {}
|
|
@@ -3496,7 +2363,7 @@ class AcceptedWorkTracker {
|
|
|
3496
2363
|
}));
|
|
3497
2364
|
return;
|
|
3498
2365
|
}
|
|
3499
|
-
const session = this._sessions.get(
|
|
2366
|
+
const session = this._sessions.get(asSessionId(sessionId));
|
|
3500
2367
|
if (!session) {
|
|
3501
2368
|
res.writeHead(404, {
|
|
3502
2369
|
'Content-Type': 'application/json'
|
|
@@ -3549,7 +2416,7 @@ class AcceptedWorkTracker {
|
|
|
3549
2416
|
};
|
|
3550
2417
|
}
|
|
3551
2418
|
// Check if session exists
|
|
3552
|
-
const session = this._sessions.get(
|
|
2419
|
+
const session = this._sessions.get(asSessionId(headerSessionId));
|
|
3553
2420
|
if (session) {
|
|
3554
2421
|
session.lastActivityAt = Date.now();
|
|
3555
2422
|
return headerSessionId;
|
|
@@ -3569,7 +2436,7 @@ class AcceptedWorkTracker {
|
|
|
3569
2436
|
lastActivityAt: Date.now(),
|
|
3570
2437
|
notificationStreams: new Set()
|
|
3571
2438
|
};
|
|
3572
|
-
this._sessions.set(
|
|
2439
|
+
this._sessions.set(asSessionId(newSessionId), sessionState);
|
|
3573
2440
|
this.log('info', `New session created: ${newSessionId}`);
|
|
3574
2441
|
this._updateSessionMetrics();
|
|
3575
2442
|
return newSessionId;
|
|
@@ -3600,7 +2467,7 @@ class AcceptedWorkTracker {
|
|
|
3600
2467
|
* @param event - SSE event name
|
|
3601
2468
|
* @param data - Event payload
|
|
3602
2469
|
*/ broadcastToSession(sessionId, event, data) {
|
|
3603
|
-
const session = this._sessions.get(
|
|
2470
|
+
const session = this._sessions.get(asSessionId(sessionId));
|
|
3604
2471
|
if (!session) {
|
|
3605
2472
|
return;
|
|
3606
2473
|
}
|
|
@@ -3741,76 +2608,12 @@ class AcceptedWorkTracker {
|
|
|
3741
2608
|
*
|
|
3742
2609
|
* @example
|
|
3743
2610
|
* ```typescript
|
|
3744
|
-
* const transport = createStreamableHttpTransport({ port: 3000, stateful: true });
|
|
3745
|
-
* await transport.connect(server);
|
|
3746
|
-
* ```
|
|
3747
|
-
*/ function createStreamableHttpTransport(options = {}) {
|
|
3748
|
-
return new StreamableHttpTransport(options);
|
|
3749
|
-
}
|
|
3750
|
-
|
|
3751
|
-
|
|
3752
|
-
},
|
|
3753
|
-
"h"(__unused_rspack_module, __webpack_exports__, __webpack_require__) {
|
|
3754
|
-
/**
|
|
3755
|
-
* Shared utility helpers.
|
|
3756
|
-
*
|
|
3757
|
-
* @module utils
|
|
3758
|
-
*/ /**
|
|
3759
|
-
* Asserts that a value is `never`. Use in switch default cases to enforce
|
|
3760
|
-
* exhaustiveness over discriminated unions. TypeScript will error at compile
|
|
3761
|
-
* time if any variant of the union is unhandled.
|
|
3762
|
-
*
|
|
3763
|
-
* @param value - The value that should be statically `never`.
|
|
3764
|
-
* @param message - Optional error message override.
|
|
3765
|
-
* @returns Never returns; always throws.
|
|
3766
|
-
*
|
|
3767
|
-
* @example
|
|
3768
|
-
* ```ts
|
|
3769
|
-
* function handle(t: ThoughtType): string {
|
|
3770
|
-
* switch (t) {
|
|
3771
|
-
* case 'regular': return 'r';
|
|
3772
|
-
* // ... all other cases ...
|
|
3773
|
-
* default: assertNever(t);
|
|
3774
|
-
* }
|
|
3775
|
-
* }
|
|
3776
|
-
* ```
|
|
3777
|
-
*/ function assertNever(value, message) {
|
|
3778
|
-
throw new Error(message ?? `Unexpected value: ${String(value)}`);
|
|
3779
|
-
}
|
|
3780
|
-
|
|
3781
|
-
__webpack_require__.d(__webpack_exports__, {
|
|
3782
|
-
x: () => (assertNever)
|
|
3783
|
-
});
|
|
3784
|
-
|
|
3785
|
-
|
|
3786
|
-
},
|
|
3787
|
-
"r"(module) {
|
|
3788
|
-
|
|
3789
|
-
module.exports = __rspack_external__lib_js_1645bc55;
|
|
3790
|
-
|
|
3791
|
-
|
|
3792
|
-
},
|
|
3793
|
-
"A"(module) {
|
|
3794
|
-
|
|
3795
|
-
module.exports = __rspack_external_node_async_hooks_4d8b1b4a;
|
|
3796
|
-
|
|
3797
|
-
|
|
3798
|
-
},
|
|
3799
|
-
"i"(module) {
|
|
3800
|
-
|
|
3801
|
-
module.exports = __rspack_external_node_crypto_2e7c4b46;
|
|
3802
|
-
|
|
3803
|
-
|
|
3804
|
-
},
|
|
3805
|
-
"S"(module) {
|
|
3806
|
-
|
|
3807
|
-
module.exports = __rspack_external_node_http_e245b239;
|
|
3808
|
-
|
|
3809
|
-
|
|
3810
|
-
},
|
|
3811
|
-
"Y"(module) {
|
|
3812
|
-
|
|
3813
|
-
module.exports = __rspack_external_node_url_3991086a;
|
|
2611
|
+
* const transport = createStreamableHttpTransport({ port: 3000, stateful: true });
|
|
2612
|
+
* await transport.connect(server);
|
|
2613
|
+
* ```
|
|
2614
|
+
*/ function createStreamableHttpTransport(options = {}) {
|
|
2615
|
+
return new StreamableHttpTransport(options);
|
|
2616
|
+
}
|
|
3814
2617
|
|
|
3815
2618
|
|
|
3816
2619
|
},
|
|
@@ -3875,8 +2678,8 @@ var __webpack_exports__ = {};
|
|
|
3875
2678
|
|
|
3876
2679
|
;// CONCATENATED MODULE: external "node:path"
|
|
3877
2680
|
|
|
3878
|
-
|
|
3879
|
-
|
|
2681
|
+
;// CONCATENATED MODULE: external "node:url"
|
|
2682
|
+
|
|
3880
2683
|
;// CONCATENATED MODULE: external "tmcp"
|
|
3881
2684
|
|
|
3882
2685
|
// EXTERNAL MODULE: ./src/errors.ts
|
|
@@ -3974,734 +2777,10 @@ function createCliShutdownHandler(lifecycle, boundary) {
|
|
|
3974
2777
|
};
|
|
3975
2778
|
}
|
|
3976
2779
|
|
|
3977
|
-
|
|
3978
|
-
var external_lib_js_ = __webpack_require__("r");
|
|
3979
|
-
;// CONCATENATED MODULE: external "node:os"
|
|
3980
|
-
|
|
3981
|
-
;// CONCATENATED MODULE: ./src/ServerConfig.ts
|
|
3982
|
-
/**
|
|
3983
|
-
* Server configuration management with validation.
|
|
3984
|
-
*
|
|
3985
|
-
* This module provides the `ServerConfig` class which handles all server configuration
|
|
3986
|
-
* with built-in validation and sensible defaults. Configuration values are validated
|
|
3987
|
-
* on construction and warnings are emitted for out-of-range values.
|
|
3988
|
-
*
|
|
3989
|
-
* @module ServerConfig
|
|
3990
|
-
*/
|
|
3991
|
-
|
|
3992
|
-
|
|
3993
|
-
/**
|
|
3994
|
-
* Server configuration with validation and defaults.
|
|
3995
|
-
*
|
|
3996
|
-
* This class manages all server configuration including history limits,
|
|
3997
|
-
* branch limits, discovery directories, cache settings, and persistence.
|
|
3998
|
-
* All values are validated on construction with appropriate defaults applied.
|
|
3999
|
-
*
|
|
4000
|
-
* @remarks
|
|
4001
|
-
* - Values outside recommended ranges trigger warnings but are still applied
|
|
4002
|
-
* - Environment variables override file-based configuration
|
|
4003
|
-
* - The `toJSON()` method provides a plain object representation
|
|
4004
|
-
*
|
|
4005
|
-
* @example
|
|
4006
|
-
* ```typescript
|
|
4007
|
-
* // Using defaults
|
|
4008
|
-
* const config1 = new ServerConfig();
|
|
4009
|
-
* console.log(config1.maxHistorySize); // 10000
|
|
4010
|
-
*
|
|
4011
|
-
* // With custom options
|
|
4012
|
-
* const config2 = new ServerConfig({
|
|
4013
|
-
* maxHistorySize: 500,
|
|
4014
|
-
* persistence: { enabled: true, backend: 'file', options: { dataDir: './data' } }
|
|
4015
|
-
* });
|
|
4016
|
-
*
|
|
4017
|
-
* // Export as plain object
|
|
4018
|
-
* const json = config2.toJSON();
|
|
4019
|
-
* ```
|
|
4020
|
-
*/ class ServerConfig {
|
|
4021
|
-
/** Maximum number of thoughts to keep in history. */ maxHistorySize;
|
|
4022
|
-
/** Maximum number of branches to maintain. */ maxBranches;
|
|
4023
|
-
/** Maximum size of each branch. */ maxBranchSize;
|
|
4024
|
-
/** Directory paths to search for skills. */ skillDirs;
|
|
4025
|
-
/** Directory paths to search for tools. */ toolDirs;
|
|
4026
|
-
/** Discovery cache configuration. */ discoveryCache;
|
|
4027
|
-
/** Persistence configuration. */ persistence;
|
|
4028
|
-
/** Maximum number of thoughts to buffer before flushing to persistence. */ persistenceBufferSize;
|
|
4029
|
-
/** Interval in milliseconds between periodic persistence flushes. */ persistenceFlushInterval;
|
|
4030
|
-
/** Maximum number of retries for failed persistence flushes. */ persistenceMaxRetries;
|
|
4031
|
-
/** Feature flag toggles. */ features;
|
|
4032
|
-
/** TTL in milliseconds for suspended tool-interleave entries. */ toolInterleaveTtlMs;
|
|
4033
|
-
/** Sweep interval in milliseconds for SuspensionStore expiration cleanup. */ toolInterleaveSweepMs;
|
|
4034
|
-
/** Maximum sessions per owner (LRU per-owner bucket). */ maxSessionsPerOwner;
|
|
4035
|
-
/**
|
|
4036
|
-
* Creates a new ServerConfig instance with validation.
|
|
4037
|
-
*
|
|
4038
|
-
* All values are validated and defaults are applied for undefined options.
|
|
4039
|
-
* Warnings are emitted to console for values outside recommended ranges.
|
|
4040
|
-
*
|
|
4041
|
-
* @param options - Optional configuration overrides
|
|
4042
|
-
*
|
|
4043
|
-
* @example
|
|
4044
|
-
* ```typescript
|
|
4045
|
-
* const config = new ServerConfig({
|
|
4046
|
-
* maxHistorySize: 500,
|
|
4047
|
-
* skillDirs: ['./my-skills']
|
|
4048
|
-
* });
|
|
4049
|
-
* ```
|
|
4050
|
-
*/ constructor(options = {}){
|
|
4051
|
-
this.maxHistorySize = this.validateMaxHistorySize(options.maxHistorySize);
|
|
4052
|
-
this.maxBranches = this.validateMaxBranches(options.maxBranches);
|
|
4053
|
-
this.maxBranchSize = this.validateMaxBranchSize(options.maxBranchSize);
|
|
4054
|
-
this.skillDirs = this.validateSkillDirs(options.skillDirs);
|
|
4055
|
-
this.toolDirs = this.validateToolDirs(options.toolDirs);
|
|
4056
|
-
this.discoveryCache = this.validateDiscoveryCache(options.discoveryCache);
|
|
4057
|
-
this.persistence = this.validatePersistence(options.persistence);
|
|
4058
|
-
this.persistenceBufferSize = this.validatePersistenceBufferSize(options.persistenceBufferSize);
|
|
4059
|
-
this.persistenceFlushInterval = this.validatePersistenceFlushInterval(options.persistenceFlushInterval);
|
|
4060
|
-
this.persistenceMaxRetries = this.validatePersistenceMaxRetries(options.persistenceMaxRetries);
|
|
4061
|
-
this.features = this.validateFeatures(options.features);
|
|
4062
|
-
this.toolInterleaveTtlMs = this.validatePositiveMs(options.toolInterleaveTtlMs, 60000, 'toolInterleaveTtlMs');
|
|
4063
|
-
this.toolInterleaveSweepMs = this.validatePositiveMs(options.toolInterleaveSweepMs, 60000, 'toolInterleaveSweepMs');
|
|
4064
|
-
this.maxSessionsPerOwner = this.validateMaxSessionsPerOwner(options.maxSessionsPerOwner);
|
|
4065
|
-
}
|
|
4066
|
-
/**
|
|
4067
|
-
* Validates the max history size value.
|
|
4068
|
-
* @param value - The value to validate
|
|
4069
|
-
* @returns The validated value or default (1000)
|
|
4070
|
-
* @private
|
|
4071
|
-
*/ validateMaxHistorySize(value) {
|
|
4072
|
-
const defaultValue = 10000;
|
|
4073
|
-
if (value === undefined || value === null) return defaultValue;
|
|
4074
|
-
if (typeof value !== 'number' || !Number.isFinite(value)) {
|
|
4075
|
-
throw new errors/* .ConfigurationError */.j1(`maxHistorySize must be a finite number, got ${value}`);
|
|
4076
|
-
}
|
|
4077
|
-
if (value < 1) {
|
|
4078
|
-
throw new errors/* .ConfigurationError */.j1(`maxHistorySize must be at least 1, got ${value}`);
|
|
4079
|
-
}
|
|
4080
|
-
if (value > 10000) {
|
|
4081
|
-
throw new errors/* .ConfigurationError */.j1(`maxHistorySize must not exceed 10000, got ${value}`);
|
|
4082
|
-
}
|
|
4083
|
-
return value;
|
|
4084
|
-
}
|
|
4085
|
-
/**
|
|
4086
|
-
* Validates the max branches value.
|
|
4087
|
-
* @param value - The value to validate
|
|
4088
|
-
* @returns The validated value or default (50)
|
|
4089
|
-
* @private
|
|
4090
|
-
*/ validateMaxBranches(value) {
|
|
4091
|
-
const defaultValue = 50;
|
|
4092
|
-
if (value === undefined || value === null) return defaultValue;
|
|
4093
|
-
if (typeof value !== 'number' || !Number.isFinite(value)) {
|
|
4094
|
-
throw new errors/* .ConfigurationError */.j1(`maxBranches must be a finite number, got ${value}`);
|
|
4095
|
-
}
|
|
4096
|
-
if (value < 0) {
|
|
4097
|
-
throw new errors/* .ConfigurationError */.j1(`maxBranches must be non-negative, got ${value}`);
|
|
4098
|
-
}
|
|
4099
|
-
if (value > 1000) {
|
|
4100
|
-
throw new errors/* .ConfigurationError */.j1(`maxBranches must not exceed 1000, got ${value}`);
|
|
4101
|
-
}
|
|
4102
|
-
return value;
|
|
4103
|
-
}
|
|
4104
|
-
/**
|
|
4105
|
-
* Validates the max branch size value.
|
|
4106
|
-
* @param value - The value to validate
|
|
4107
|
-
* @returns The validated value or default (100)
|
|
4108
|
-
* @private
|
|
4109
|
-
*/ validateMaxBranchSize(value) {
|
|
4110
|
-
const defaultValue = 100;
|
|
4111
|
-
if (value === undefined || value === null) return defaultValue;
|
|
4112
|
-
if (typeof value !== 'number' || !Number.isFinite(value)) {
|
|
4113
|
-
throw new errors/* .ConfigurationError */.j1(`maxBranchSize must be a finite number, got ${value}`);
|
|
4114
|
-
}
|
|
4115
|
-
if (value < 1) {
|
|
4116
|
-
throw new errors/* .ConfigurationError */.j1(`maxBranchSize must be at least 1, got ${value}`);
|
|
4117
|
-
}
|
|
4118
|
-
if (value > 1000) {
|
|
4119
|
-
throw new errors/* .ConfigurationError */.j1(`maxBranchSize must not exceed 1000, got ${value}`);
|
|
4120
|
-
}
|
|
4121
|
-
return value;
|
|
4122
|
-
}
|
|
4123
|
-
/**
|
|
4124
|
-
* Validates the skill directories value.
|
|
4125
|
-
* @param value - The value to validate
|
|
4126
|
-
* @returns The validated value or default ['.claude/skills', '~/.claude/skills', '.agents/skills', '~/.agents/skills']
|
|
4127
|
-
* @private
|
|
4128
|
-
*/ validateSkillDirs(value) {
|
|
4129
|
-
const defaultValue = [
|
|
4130
|
-
'.claude/skills',
|
|
4131
|
-
join(homedir(), '.claude/skills'),
|
|
4132
|
-
'.agents/skills',
|
|
4133
|
-
join(homedir(), '.agents/skills')
|
|
4134
|
-
];
|
|
4135
|
-
return value === undefined ? defaultValue : [
|
|
4136
|
-
...value
|
|
4137
|
-
];
|
|
4138
|
-
}
|
|
4139
|
-
validateToolDirs(value) {
|
|
4140
|
-
const defaultValue = [
|
|
4141
|
-
'.claude/tools',
|
|
4142
|
-
join(homedir(), '.claude/tools')
|
|
4143
|
-
];
|
|
4144
|
-
return value === undefined ? defaultValue : [
|
|
4145
|
-
...value
|
|
4146
|
-
];
|
|
4147
|
-
}
|
|
4148
|
-
/**
|
|
4149
|
-
* Validates the discovery cache configuration.
|
|
4150
|
-
* @param value - The value to validate
|
|
4151
|
-
* @returns The validated value with defaults applied
|
|
4152
|
-
* @private
|
|
4153
|
-
*/ validateDiscoveryCache(value) {
|
|
4154
|
-
return {
|
|
4155
|
-
ttl: value?.ttl ?? 300000,
|
|
4156
|
-
maxSize: value?.maxSize ?? 100
|
|
4157
|
-
};
|
|
4158
|
-
}
|
|
4159
|
-
/**
|
|
4160
|
-
* Validates the persistence configuration.
|
|
4161
|
-
* @param value - The value to validate
|
|
4162
|
-
* @returns The validated value with defaults applied
|
|
4163
|
-
* @private
|
|
4164
|
-
*/ validatePersistence(value) {
|
|
4165
|
-
if (!value) {
|
|
4166
|
-
// Default to in-memory (no actual persistence, just consistency)
|
|
4167
|
-
return {
|
|
4168
|
-
enabled: false,
|
|
4169
|
-
backend: 'memory'
|
|
4170
|
-
};
|
|
4171
|
-
}
|
|
4172
|
-
// Validate backend type
|
|
4173
|
-
const validBackends = [
|
|
4174
|
-
'file',
|
|
4175
|
-
'sqlite',
|
|
4176
|
-
'memory'
|
|
4177
|
-
];
|
|
4178
|
-
const backend = value.backend ?? 'memory';
|
|
4179
|
-
if (!validBackends.includes(backend)) {
|
|
4180
|
-
throw new errors/* .ConfigurationError */.j1(`persistence.backend must be one of ${validBackends.join(', ')}, got ${backend}`);
|
|
4181
|
-
}
|
|
4182
|
-
return {
|
|
4183
|
-
enabled: value.enabled ?? false,
|
|
4184
|
-
backend,
|
|
4185
|
-
options: value.options ?? {}
|
|
4186
|
-
};
|
|
4187
|
-
}
|
|
4188
|
-
/**
|
|
4189
|
-
* Validates the persistence buffer size value.
|
|
4190
|
-
* @param value - The value to validate
|
|
4191
|
-
* @returns The validated value or default (100)
|
|
4192
|
-
* @private
|
|
4193
|
-
*/ validatePersistenceBufferSize(value) {
|
|
4194
|
-
const defaultValue = 100;
|
|
4195
|
-
if (value === undefined || value === null) return defaultValue;
|
|
4196
|
-
if (typeof value !== 'number' || !Number.isFinite(value)) {
|
|
4197
|
-
throw new errors/* .ConfigurationError */.j1(`persistenceBufferSize must be a finite number, got ${value}`);
|
|
4198
|
-
}
|
|
4199
|
-
if (value < 1) {
|
|
4200
|
-
throw new errors/* .ConfigurationError */.j1(`persistenceBufferSize must be at least 1, got ${value}`);
|
|
4201
|
-
}
|
|
4202
|
-
if (value > 10000) {
|
|
4203
|
-
throw new errors/* .ConfigurationError */.j1(`persistenceBufferSize must not exceed 10000, got ${value}`);
|
|
4204
|
-
}
|
|
4205
|
-
return value;
|
|
4206
|
-
}
|
|
4207
|
-
/**
|
|
4208
|
-
* Validates the persistence flush interval value.
|
|
4209
|
-
* @param value - The value to validate
|
|
4210
|
-
* @returns The validated value or default (1000)
|
|
4211
|
-
* @private
|
|
4212
|
-
*/ validatePersistenceFlushInterval(value) {
|
|
4213
|
-
const defaultValue = 1000;
|
|
4214
|
-
if (value === undefined || value === null) return defaultValue;
|
|
4215
|
-
if (typeof value !== 'number' || !Number.isFinite(value)) {
|
|
4216
|
-
throw new errors/* .ConfigurationError */.j1(`persistenceFlushInterval must be a finite number, got ${value}`);
|
|
4217
|
-
}
|
|
4218
|
-
if (value < 100) {
|
|
4219
|
-
throw new errors/* .ConfigurationError */.j1(`persistenceFlushInterval must be at least 100, got ${value}`);
|
|
4220
|
-
}
|
|
4221
|
-
if (value > 60000) {
|
|
4222
|
-
throw new errors/* .ConfigurationError */.j1(`persistenceFlushInterval must not exceed 60000, got ${value}`);
|
|
4223
|
-
}
|
|
4224
|
-
return value;
|
|
4225
|
-
}
|
|
4226
|
-
/**
|
|
4227
|
-
* Validates the persistence max retries value.
|
|
4228
|
-
* @param value - The value to validate
|
|
4229
|
-
* @returns The validated value or default (3)
|
|
4230
|
-
* @private
|
|
4231
|
-
*/ validatePersistenceMaxRetries(value) {
|
|
4232
|
-
const defaultValue = 3;
|
|
4233
|
-
if (value === undefined || value === null) return defaultValue;
|
|
4234
|
-
if (typeof value !== 'number' || !Number.isFinite(value)) {
|
|
4235
|
-
throw new errors/* .ConfigurationError */.j1(`persistenceMaxRetries must be a finite number, got ${value}`);
|
|
4236
|
-
}
|
|
4237
|
-
if (value < 0) {
|
|
4238
|
-
throw new errors/* .ConfigurationError */.j1(`persistenceMaxRetries must be non-negative, got ${value}`);
|
|
4239
|
-
}
|
|
4240
|
-
if (value > 10) {
|
|
4241
|
-
throw new errors/* .ConfigurationError */.j1(`persistenceMaxRetries must not exceed 10, got ${value}`);
|
|
4242
|
-
}
|
|
4243
|
-
return value;
|
|
4244
|
-
}
|
|
4245
|
-
/**
|
|
4246
|
-
* Validates feature flags and fills defaults for missing fields.
|
|
4247
|
-
* @param value - Partial feature flag overrides
|
|
4248
|
-
* @returns Fully populated FeatureFlags with defaults applied
|
|
4249
|
-
* @private
|
|
4250
|
-
*/ validateFeatures(value) {
|
|
4251
|
-
const reasoningStrategy = value?.reasoningStrategy ?? 'sequential';
|
|
4252
|
-
if (reasoningStrategy !== 'sequential' && reasoningStrategy !== 'tot') {
|
|
4253
|
-
throw new errors/* .ConfigurationError */.j1(`features.reasoningStrategy must be one of sequential, tot, got ${reasoningStrategy}`);
|
|
4254
|
-
}
|
|
4255
|
-
return {
|
|
4256
|
-
dagEdges: value?.dagEdges ?? true,
|
|
4257
|
-
reasoningStrategy,
|
|
4258
|
-
calibration: value?.calibration ?? true,
|
|
4259
|
-
compression: value?.compression ?? true,
|
|
4260
|
-
toolInterleave: value?.toolInterleave ?? true,
|
|
4261
|
-
newThoughtTypes: value?.newThoughtTypes ?? true,
|
|
4262
|
-
outcomeRecording: value?.outcomeRecording ?? true
|
|
4263
|
-
};
|
|
4264
|
-
}
|
|
4265
|
-
/**
|
|
4266
|
-
* Validates a positive millisecond value with a default fallback.
|
|
4267
|
-
* @param value - The value to validate
|
|
4268
|
-
* @param defaultValue - Default applied if value is undefined/null
|
|
4269
|
-
* @param fieldName - Field name for error messages
|
|
4270
|
-
* @returns The validated millisecond value
|
|
4271
|
-
* @private
|
|
4272
|
-
*/ validatePositiveMs(value, defaultValue, fieldName) {
|
|
4273
|
-
if (value === undefined || value === null) return defaultValue;
|
|
4274
|
-
if (typeof value !== 'number' || !Number.isFinite(value)) {
|
|
4275
|
-
throw new errors/* .ConfigurationError */.j1(`${fieldName} must be a finite number, got ${value}`);
|
|
4276
|
-
}
|
|
4277
|
-
if (value < 1) {
|
|
4278
|
-
throw new errors/* .ConfigurationError */.j1(`${fieldName} must be at least 1, got ${value}`);
|
|
4279
|
-
}
|
|
4280
|
-
return value;
|
|
4281
|
-
}
|
|
4282
|
-
/**
|
|
4283
|
-
* Validates the max sessions per owner value.
|
|
4284
|
-
* @param value - The value to validate
|
|
4285
|
-
* @returns The validated value or default (50)
|
|
4286
|
-
* @private
|
|
4287
|
-
*/ validateMaxSessionsPerOwner(value) {
|
|
4288
|
-
const defaultValue = 50;
|
|
4289
|
-
if (value === undefined || value === null) return defaultValue;
|
|
4290
|
-
if (typeof value !== 'number' || !Number.isFinite(value)) {
|
|
4291
|
-
throw new errors/* .ConfigurationError */.j1(`maxSessionsPerOwner must be a finite number, got ${value}`);
|
|
4292
|
-
}
|
|
4293
|
-
if (value < 1) {
|
|
4294
|
-
throw new errors/* .ConfigurationError */.j1(`maxSessionsPerOwner must be at least 1, got ${value}`);
|
|
4295
|
-
}
|
|
4296
|
-
if (value > 10000) {
|
|
4297
|
-
throw new errors/* .ConfigurationError */.j1(`maxSessionsPerOwner must not exceed 10000, got ${value}`);
|
|
4298
|
-
}
|
|
4299
|
-
return value;
|
|
4300
|
-
}
|
|
4301
|
-
/**
|
|
4302
|
-
* Converts the configuration to a plain object.
|
|
4303
|
-
*
|
|
4304
|
-
* Useful for serialization, logging, or when a plain object representation
|
|
4305
|
-
* is preferred over the ServerConfig instance.
|
|
4306
|
-
*
|
|
4307
|
-
* @returns A plain object representation of the configuration
|
|
4308
|
-
*
|
|
4309
|
-
* @example
|
|
4310
|
-
* ```typescript
|
|
4311
|
-
* const config = new ServerConfig({ maxHistorySize: 500 });
|
|
4312
|
-
* const json = config.toJSON();
|
|
4313
|
-
* console.log(JSON.stringify(json, null, 2));
|
|
4314
|
-
* ```
|
|
4315
|
-
*/ toJSON() {
|
|
4316
|
-
return {
|
|
4317
|
-
maxHistorySize: this.maxHistorySize,
|
|
4318
|
-
maxBranches: this.maxBranches,
|
|
4319
|
-
maxBranchSize: this.maxBranchSize,
|
|
4320
|
-
skillDirs: this.skillDirs,
|
|
4321
|
-
toolDirs: this.toolDirs,
|
|
4322
|
-
discoveryCache: this.discoveryCache,
|
|
4323
|
-
persistence: this.persistence,
|
|
4324
|
-
persistenceBufferSize: this.persistenceBufferSize,
|
|
4325
|
-
persistenceFlushInterval: this.persistenceFlushInterval,
|
|
4326
|
-
persistenceMaxRetries: this.persistenceMaxRetries,
|
|
4327
|
-
features: this.features,
|
|
4328
|
-
toolInterleaveTtlMs: this.toolInterleaveTtlMs,
|
|
4329
|
-
toolInterleaveSweepMs: this.toolInterleaveSweepMs,
|
|
4330
|
-
maxSessionsPerOwner: this.maxSessionsPerOwner
|
|
4331
|
-
};
|
|
4332
|
-
}
|
|
4333
|
-
}
|
|
4334
|
-
|
|
4335
|
-
;// CONCATENATED MODULE: external "yaml"
|
|
4336
|
-
|
|
4337
|
-
// EXTERNAL MODULE: external "valibot"
|
|
4338
|
-
var external_valibot_ = __webpack_require__("w");
|
|
4339
|
-
;// CONCATENATED MODULE: ./src/config/ConfigLoader.ts
|
|
4340
|
-
/**
|
|
4341
|
-
* Configuration file loading with environment variable override support.
|
|
4342
|
-
*
|
|
4343
|
-
* This module provides the `ConfigLoader` class which handles loading configuration
|
|
4344
|
-
* from YAML and JSON files in standard locations, with automatic environment variable
|
|
4345
|
-
* overrides for all settings.
|
|
4346
|
-
*
|
|
4347
|
-
* @module config
|
|
4348
|
-
*/
|
|
4349
|
-
|
|
4350
|
-
|
|
4351
|
-
|
|
4352
|
-
|
|
4353
|
-
|
|
4354
|
-
/**
|
|
4355
|
-
* Lenient runtime schema for config files. Only validates top-level shape;
|
|
4356
|
-
* unknown extra fields are preserved by Valibot's default object behavior
|
|
4357
|
-
* being strict is avoided by using `v.looseObject`. All fields are optional.
|
|
4358
|
-
*/ const ConfigFileOptionsSchema = external_valibot_.looseObject({
|
|
4359
|
-
maxHistorySize: external_valibot_.optional(external_valibot_.number()),
|
|
4360
|
-
maxBranches: external_valibot_.optional(external_valibot_.number()),
|
|
4361
|
-
maxBranchSize: external_valibot_.optional(external_valibot_.number()),
|
|
4362
|
-
logLevel: external_valibot_.optional(external_valibot_.picklist([
|
|
4363
|
-
'debug',
|
|
4364
|
-
'info',
|
|
4365
|
-
'warn',
|
|
4366
|
-
'error'
|
|
4367
|
-
])),
|
|
4368
|
-
prettyLog: external_valibot_.optional(external_valibot_.boolean()),
|
|
4369
|
-
skillDirs: external_valibot_.optional(external_valibot_.array(external_valibot_.string())),
|
|
4370
|
-
toolDirs: external_valibot_.optional(external_valibot_.array(external_valibot_.string())),
|
|
4371
|
-
discoveryCache: external_valibot_.optional(external_valibot_.looseObject({
|
|
4372
|
-
ttl: external_valibot_.optional(external_valibot_.number()),
|
|
4373
|
-
maxSize: external_valibot_.optional(external_valibot_.number())
|
|
4374
|
-
})),
|
|
4375
|
-
persistence: external_valibot_.optional(external_valibot_.looseObject({})),
|
|
4376
|
-
features: external_valibot_.optional(external_valibot_.looseObject({})),
|
|
4377
|
-
toolInterleaveTtlMs: external_valibot_.optional(external_valibot_.number()),
|
|
4378
|
-
toolInterleaveSweepMs: external_valibot_.optional(external_valibot_.number()),
|
|
4379
|
-
maxSessionsPerOwner: external_valibot_.optional(external_valibot_.number())
|
|
4380
|
-
});
|
|
4381
|
-
/**
|
|
4382
|
-
* Loads configuration from files with environment variable overrides.
|
|
4383
|
-
*
|
|
4384
|
-
* This class searches for configuration files in standard locations and applies
|
|
4385
|
-
* environment variable overrides. Files are searched in priority order, with the
|
|
4386
|
-
* first match being used. Environment variables always take precedence over file values.
|
|
4387
|
-
*
|
|
4388
|
-
* @remarks
|
|
4389
|
-
* **Config File Search Order (priority):**
|
|
4390
|
-
* 1. Custom path (if provided to constructor)
|
|
4391
|
-
* 2. `.claude/config.json` (project-local)
|
|
4392
|
-
* 3. `.claude/config.yaml` (project-local)
|
|
4393
|
-
* 4. `.claude/config.yml` (project-local)
|
|
4394
|
-
* 5. `~/.claude/config.json` (user-global)
|
|
4395
|
-
* 6. `~/.claude/config.yaml` (user-global)
|
|
4396
|
-
* 7. `~/.claude/config.yml` (user-global)
|
|
4397
|
-
*
|
|
4398
|
-
* **Environment Variable Overrides:**
|
|
4399
|
-
* | Variable | Type | Description |
|
|
4400
|
-
* |----------|------|-------------|
|
|
4401
|
-
* | `MAX_HISTORY_SIZE` | number | Max thoughts in history |
|
|
4402
|
-
* | `MAX_BRANCHES` | number | Max number of branches |
|
|
4403
|
-
* | `MAX_BRANCH_SIZE` | number | Max size of each branch |
|
|
4404
|
-
* | `LOG_LEVEL` | string | Logging level (debug/info/warn/error) |
|
|
4405
|
-
* | `PRETTY_LOG` | string | "false" to disable pretty logging |
|
|
4406
|
-
* | `SKILL_DIRS` | string | Colon-separated directory paths |
|
|
4407
|
-
* | `TOOL_DIRS` | string | Colon-separated directory paths |
|
|
4408
|
-
* | `DISCOVERY_CACHE_TTL` | number | TTL in seconds (converted to ms) |
|
|
4409
|
-
* | `DISCOVERY_CACHE_MAX_SIZE` | number | Max cache entries |
|
|
4410
|
-
*
|
|
4411
|
-
* @example
|
|
4412
|
-
* ```typescript
|
|
4413
|
-
* // Use default search paths
|
|
4414
|
-
* const loader1 = new ConfigLoader();
|
|
4415
|
-
* const config1 = loader1.load();
|
|
4416
|
-
*
|
|
4417
|
-
* // Use custom config path
|
|
4418
|
-
* const loader2 = new ConfigLoader('./my-config.yaml');
|
|
4419
|
-
* const config2 = loader2.load();
|
|
4420
|
-
*
|
|
4421
|
-
* // Convert to ServerConfig options
|
|
4422
|
-
* const serverOptions = loader2.toServerConfigOptions(config2);
|
|
4423
|
-
* ```
|
|
4424
|
-
*/ class ConfigLoader {
|
|
4425
|
-
/** Array of config file paths to search, in priority order. */ _configPaths;
|
|
4426
|
-
/**
|
|
4427
|
-
* Creates a new ConfigLoader instance.
|
|
4428
|
-
*
|
|
4429
|
-
* @param customPath - Optional custom config file path. If provided, only this path will be checked.
|
|
4430
|
-
*
|
|
4431
|
-
* @example
|
|
4432
|
-
* ```typescript
|
|
4433
|
-
* // Use default search paths
|
|
4434
|
-
* const loader1 = new ConfigLoader();
|
|
4435
|
-
*
|
|
4436
|
-
* // Use a specific config file
|
|
4437
|
-
* const loader2 = new ConfigLoader('./custom-config.json');
|
|
4438
|
-
* ```
|
|
4439
|
-
*/ constructor(customPath){
|
|
4440
|
-
this._configPaths = customPath ? [
|
|
4441
|
-
customPath
|
|
4442
|
-
] : [
|
|
4443
|
-
'.claude/config.json',
|
|
4444
|
-
'.claude/config.yaml',
|
|
4445
|
-
'.claude/config.yml',
|
|
4446
|
-
join(homedir(), '.claude/config.json'),
|
|
4447
|
-
join(homedir(), '.claude/config.yaml'),
|
|
4448
|
-
join(homedir(), '.claude/config.yml')
|
|
4449
|
-
];
|
|
4450
|
-
}
|
|
4451
|
-
/**
|
|
4452
|
-
* Loads configuration from files and applies environment overrides.
|
|
4453
|
-
*
|
|
4454
|
-
* Searches for config files in the configured paths (in priority order),
|
|
4455
|
-
* parses the first match, and applies environment variable overrides.
|
|
4456
|
-
* Returns null if no config file is found and no environment overrides are set.
|
|
4457
|
-
*
|
|
4458
|
-
* @returns The loaded configuration with environment overrides applied, or null if no config found
|
|
4459
|
-
*
|
|
4460
|
-
* @example
|
|
4461
|
-
* ```typescript
|
|
4462
|
-
* const loader = new ConfigLoader();
|
|
4463
|
-
* const config = loader.load();
|
|
4464
|
-
*
|
|
4465
|
-
* if (config) {
|
|
4466
|
-
* console.log('Max history size:', config.maxHistorySize);
|
|
4467
|
-
* console.log('Log level:', config.logLevel);
|
|
4468
|
-
* }
|
|
4469
|
-
* ```
|
|
4470
|
-
*/ load() {
|
|
4471
|
-
let config = null;
|
|
4472
|
-
for (const configPath of this._configPaths){
|
|
4473
|
-
if (existsSync(configPath)) {
|
|
4474
|
-
try {
|
|
4475
|
-
config = this.parseConfig(configPath);
|
|
4476
|
-
break;
|
|
4477
|
-
} catch (error) {
|
|
4478
|
-
console.error(`Failed to load config from ${configPath}:`, (0,errors/* .getErrorMessage */.u1)(error));
|
|
4479
|
-
}
|
|
4480
|
-
}
|
|
4481
|
-
}
|
|
4482
|
-
return this.applyEnvironmentOverrides(config || {});
|
|
4483
|
-
}
|
|
4484
|
-
/**
|
|
4485
|
-
* Applies environment variable overrides to the configuration.
|
|
4486
|
-
*
|
|
4487
|
-
* Environment variables take precedence over file-based configuration.
|
|
4488
|
-
* Supported environment variables:
|
|
4489
|
-
* - `MAX_HISTORY_SIZE`, `MAX_BRANCHES`, `MAX_BRANCH_SIZE` (numbers)
|
|
4490
|
-
* - `LOG_LEVEL` (debug/info/warn/error)
|
|
4491
|
-
* - `PRETTY_LOG` ("false" to disable)
|
|
4492
|
-
* - `SKILL_DIRS` (colon-separated paths)
|
|
4493
|
-
* - `TOOL_DIRS` (colon-separated paths)
|
|
4494
|
-
* - `DISCOVERY_CACHE_TTL` (in seconds, converted to ms)
|
|
4495
|
-
* - `DISCOVERY_CACHE_MAX_SIZE` (number)
|
|
4496
|
-
*
|
|
4497
|
-
* @param config - The configuration to apply overrides to
|
|
4498
|
-
* @returns A new configuration object with environment overrides applied
|
|
4499
|
-
*/ applyEnvironmentOverrides(config) {
|
|
4500
|
-
const result = {
|
|
4501
|
-
...config,
|
|
4502
|
-
...config.skillDirs === undefined ? {} : {
|
|
4503
|
-
skillDirs: [
|
|
4504
|
-
...config.skillDirs
|
|
4505
|
-
]
|
|
4506
|
-
},
|
|
4507
|
-
...config.toolDirs === undefined ? {} : {
|
|
4508
|
-
toolDirs: [
|
|
4509
|
-
...config.toolDirs
|
|
4510
|
-
]
|
|
4511
|
-
},
|
|
4512
|
-
...config.discoveryCache === undefined ? {} : {
|
|
4513
|
-
discoveryCache: {
|
|
4514
|
-
...config.discoveryCache
|
|
4515
|
-
}
|
|
4516
|
-
},
|
|
4517
|
-
...config.persistence === undefined ? {} : {
|
|
4518
|
-
persistence: {
|
|
4519
|
-
...config.persistence,
|
|
4520
|
-
...config.persistence.options === undefined ? {} : {
|
|
4521
|
-
options: {
|
|
4522
|
-
...config.persistence.options
|
|
4523
|
-
}
|
|
4524
|
-
}
|
|
4525
|
-
}
|
|
4526
|
-
},
|
|
4527
|
-
...config.features === undefined ? {} : {
|
|
4528
|
-
features: {
|
|
4529
|
-
...config.features
|
|
4530
|
-
}
|
|
4531
|
-
}
|
|
4532
|
-
};
|
|
4533
|
-
if (process.env.MAX_HISTORY_SIZE !== undefined) {
|
|
4534
|
-
result.maxHistorySize = this.parseEnvironmentInteger('MAX_HISTORY_SIZE', process.env.MAX_HISTORY_SIZE);
|
|
4535
|
-
}
|
|
4536
|
-
if (process.env.MAX_BRANCHES !== undefined) {
|
|
4537
|
-
result.maxBranches = this.parseEnvironmentInteger('MAX_BRANCHES', process.env.MAX_BRANCHES);
|
|
4538
|
-
}
|
|
4539
|
-
if (process.env.MAX_BRANCH_SIZE !== undefined) {
|
|
4540
|
-
result.maxBranchSize = this.parseEnvironmentInteger('MAX_BRANCH_SIZE', process.env.MAX_BRANCH_SIZE);
|
|
4541
|
-
}
|
|
4542
|
-
if (process.env.LOG_LEVEL && [
|
|
4543
|
-
'debug',
|
|
4544
|
-
'info',
|
|
4545
|
-
'warn',
|
|
4546
|
-
'error'
|
|
4547
|
-
].includes(process.env.LOG_LEVEL)) {
|
|
4548
|
-
result.logLevel = process.env.LOG_LEVEL;
|
|
4549
|
-
}
|
|
4550
|
-
if (process.env.PRETTY_LOG === 'false') {
|
|
4551
|
-
result.prettyLog = false;
|
|
4552
|
-
}
|
|
4553
|
-
if (process.env.SKILL_DIRS !== undefined) {
|
|
4554
|
-
result.skillDirs = process.env.SKILL_DIRS === '' ? [] : process.env.SKILL_DIRS.split(':');
|
|
4555
|
-
}
|
|
4556
|
-
if (process.env.TOOL_DIRS !== undefined) {
|
|
4557
|
-
result.toolDirs = process.env.TOOL_DIRS === '' ? [] : process.env.TOOL_DIRS.split(':');
|
|
4558
|
-
}
|
|
4559
|
-
if (process.env.DISCOVERY_CACHE_TTL !== undefined) {
|
|
4560
|
-
const seconds = this.parseEnvironmentInteger('DISCOVERY_CACHE_TTL', process.env.DISCOVERY_CACHE_TTL);
|
|
4561
|
-
const ttl = seconds * 1000;
|
|
4562
|
-
if (!Number.isSafeInteger(ttl)) {
|
|
4563
|
-
throw new errors/* .ConfigurationError */.j1('DISCOVERY_CACHE_TTL exceeds the safe integer range');
|
|
4564
|
-
}
|
|
4565
|
-
result.discoveryCache = {
|
|
4566
|
-
...result.discoveryCache,
|
|
4567
|
-
ttl
|
|
4568
|
-
};
|
|
4569
|
-
}
|
|
4570
|
-
if (process.env.DISCOVERY_CACHE_MAX_SIZE !== undefined) {
|
|
4571
|
-
const maxSize = this.parseEnvironmentInteger('DISCOVERY_CACHE_MAX_SIZE', process.env.DISCOVERY_CACHE_MAX_SIZE);
|
|
4572
|
-
result.discoveryCache = {
|
|
4573
|
-
...result.discoveryCache,
|
|
4574
|
-
maxSize
|
|
4575
|
-
};
|
|
4576
|
-
}
|
|
4577
|
-
if (process.env.TRACELATTICE_TOOL_INTERLEAVE_TTL_MS !== undefined) {
|
|
4578
|
-
result.toolInterleaveTtlMs = this.parseEnvironmentInteger('TRACELATTICE_TOOL_INTERLEAVE_TTL_MS', process.env.TRACELATTICE_TOOL_INTERLEAVE_TTL_MS);
|
|
4579
|
-
}
|
|
4580
|
-
if (process.env.TRACELATTICE_TOOL_INTERLEAVE_SWEEP_MS !== undefined) {
|
|
4581
|
-
result.toolInterleaveSweepMs = this.parseEnvironmentInteger('TRACELATTICE_TOOL_INTERLEAVE_SWEEP_MS', process.env.TRACELATTICE_TOOL_INTERLEAVE_SWEEP_MS);
|
|
4582
|
-
}
|
|
4583
|
-
if (process.env.SESSION_MAX_PER_OWNER !== undefined) {
|
|
4584
|
-
result.maxSessionsPerOwner = this.parseEnvironmentInteger('SESSION_MAX_PER_OWNER', process.env.SESSION_MAX_PER_OWNER);
|
|
4585
|
-
}
|
|
4586
|
-
this.applyFeatureFlagOverrides(result);
|
|
4587
|
-
return result;
|
|
4588
|
-
}
|
|
4589
|
-
/**
|
|
4590
|
-
* Applies TRACELATTICE_FEATURES_* environment variable overrides for feature flags.
|
|
4591
|
-
* Booleans accept 'true'/'false'/'1'/'0' (case-insensitive).
|
|
4592
|
-
* Invalid reasoningStrategy values are rejected.
|
|
4593
|
-
*
|
|
4594
|
-
* @param result - Configuration object to mutate with feature flag overrides
|
|
4595
|
-
* @private
|
|
4596
|
-
*/ applyFeatureFlagOverrides(result) {
|
|
4597
|
-
const boolMap = {
|
|
4598
|
-
TRACELATTICE_FEATURES_DAG_EDGES: 'dagEdges',
|
|
4599
|
-
TRACELATTICE_FEATURES_CALIBRATION: 'calibration',
|
|
4600
|
-
TRACELATTICE_FEATURES_COMPRESSION: 'compression',
|
|
4601
|
-
TRACELATTICE_FEATURES_TOOL_INTERLEAVE: 'toolInterleave',
|
|
4602
|
-
TRACELATTICE_FEATURES_NEW_THOUGHT_TYPES: 'newThoughtTypes',
|
|
4603
|
-
TRACELATTICE_FEATURES_OUTCOME_RECORDING: 'outcomeRecording'
|
|
4604
|
-
};
|
|
4605
|
-
for (const [envVar, key] of Object.entries(boolMap)){
|
|
4606
|
-
const raw = process.env[envVar];
|
|
4607
|
-
if (raw === undefined) continue;
|
|
4608
|
-
const parsed = this.parseBoolean(raw);
|
|
4609
|
-
if (parsed === undefined) {
|
|
4610
|
-
console.warn(`Invalid boolean value for ${envVar}: "${raw}" (expected true/false/1/0). Ignoring.`);
|
|
4611
|
-
continue;
|
|
4612
|
-
}
|
|
4613
|
-
const features = result.features ?? {};
|
|
4614
|
-
features[key] = parsed;
|
|
4615
|
-
result.features = features;
|
|
4616
|
-
}
|
|
4617
|
-
const strategyRaw = process.env.TRACELATTICE_FEATURES_REASONING_STRATEGY;
|
|
4618
|
-
if (strategyRaw !== undefined) {
|
|
4619
|
-
if (strategyRaw !== 'sequential' && strategyRaw !== 'tot') {
|
|
4620
|
-
throw new errors/* .ConfigurationError */.j1(`TRACELATTICE_FEATURES_REASONING_STRATEGY must be one of sequential, tot, got ${strategyRaw}`);
|
|
4621
|
-
}
|
|
4622
|
-
const features = result.features ?? {};
|
|
4623
|
-
features.reasoningStrategy = strategyRaw;
|
|
4624
|
-
result.features = features;
|
|
4625
|
-
}
|
|
4626
|
-
}
|
|
4627
|
-
parseEnvironmentInteger(environmentName, raw) {
|
|
4628
|
-
if (!/^(0|[1-9]\d*)$/.test(raw)) {
|
|
4629
|
-
throw new errors/* .ConfigurationError */.j1(`${environmentName} must be an integer, got ${raw}`);
|
|
4630
|
-
}
|
|
4631
|
-
const parsed = Number(raw);
|
|
4632
|
-
if (!Number.isSafeInteger(parsed)) {
|
|
4633
|
-
throw new errors/* .ConfigurationError */.j1(`${environmentName} must be a safe integer, got ${raw}`);
|
|
4634
|
-
}
|
|
4635
|
-
return parsed;
|
|
4636
|
-
}
|
|
4637
|
-
/**
|
|
4638
|
-
* Parses a boolean from an environment variable string.
|
|
4639
|
-
* Accepts 'true'/'false'/'1'/'0' case-insensitively.
|
|
4640
|
-
*
|
|
4641
|
-
* @param raw - Raw environment variable string
|
|
4642
|
-
* @returns Parsed boolean, or undefined if the value is invalid
|
|
4643
|
-
* @private
|
|
4644
|
-
*/ parseBoolean(raw) {
|
|
4645
|
-
const v = raw.trim().toLowerCase();
|
|
4646
|
-
if (v === 'true' || v === '1') return true;
|
|
4647
|
-
if (v === 'false' || v === '0') return false;
|
|
4648
|
-
return undefined;
|
|
4649
|
-
}
|
|
4650
|
-
/**
|
|
4651
|
-
* Parses a configuration file (JSON or YAML).
|
|
4652
|
-
*
|
|
4653
|
-
* Detects the file type by extension and uses the appropriate parser.
|
|
4654
|
-
* Supports `.json`, `.yaml`, and `.yml` file extensions.
|
|
4655
|
-
*
|
|
4656
|
-
* @param filePath - Path to the configuration file to parse
|
|
4657
|
-
* @returns The parsed configuration object
|
|
4658
|
-
* @throws {Error} If the file cannot be parsed
|
|
4659
|
-
* @private
|
|
4660
|
-
*/ parseConfig(filePath) {
|
|
4661
|
-
const content = readFileSync(filePath, 'utf-8');
|
|
4662
|
-
const ext = filePath.split('.').pop()?.toLowerCase();
|
|
4663
|
-
const raw = ext === 'yaml' || ext === 'yml' ? parse(content) : JSON.parse(content);
|
|
4664
|
-
return external_valibot_.parse(ConfigFileOptionsSchema, raw);
|
|
4665
|
-
}
|
|
4666
|
-
/**
|
|
4667
|
-
* Converts file-based configuration to ServerConfig options.
|
|
4668
|
-
*
|
|
4669
|
-
* This is a convenience method for extracting the ServerConfig-relevant
|
|
4670
|
-
* options from a file-based configuration.
|
|
4671
|
-
*
|
|
4672
|
-
* @param config - The configuration to convert
|
|
4673
|
-
* @returns An object with ServerConfig-compatible options
|
|
4674
|
-
*
|
|
4675
|
-
* @example
|
|
4676
|
-
* ```typescript
|
|
4677
|
-
* const loader = new ConfigLoader();
|
|
4678
|
-
* const config = loader.load();
|
|
4679
|
-
* if (config) {
|
|
4680
|
-
* const serverOpts = loader.toServerConfigOptions(config);
|
|
4681
|
-
* const serverConfig = new ServerConfig(serverOpts);
|
|
4682
|
-
* }
|
|
4683
|
-
* ```
|
|
4684
|
-
*/ toServerConfigOptions(config) {
|
|
4685
|
-
return {
|
|
4686
|
-
maxHistorySize: config.maxHistorySize,
|
|
4687
|
-
maxBranches: config.maxBranches,
|
|
4688
|
-
maxBranchSize: config.maxBranchSize,
|
|
4689
|
-
skillDirs: config.skillDirs,
|
|
4690
|
-
toolDirs: config.toolDirs,
|
|
4691
|
-
discoveryCache: config.discoveryCache,
|
|
4692
|
-
persistence: config.persistence,
|
|
4693
|
-
features: config.features,
|
|
4694
|
-
toolInterleaveTtlMs: config.toolInterleaveTtlMs,
|
|
4695
|
-
toolInterleaveSweepMs: config.toolInterleaveSweepMs,
|
|
4696
|
-
maxSessionsPerOwner: config.maxSessionsPerOwner
|
|
4697
|
-
};
|
|
4698
|
-
}
|
|
4699
|
-
}
|
|
2780
|
+
;// CONCATENATED MODULE: external "./lib.js"
|
|
4700
2781
|
|
|
4701
|
-
// EXTERNAL MODULE: ./src/
|
|
4702
|
-
var
|
|
4703
|
-
// EXTERNAL MODULE: ./src/context/RequestContext.ts
|
|
4704
|
-
var RequestContext = __webpack_require__("y");
|
|
2782
|
+
// EXTERNAL MODULE: ./src/context/RequestContext.ts + 1 modules
|
|
2783
|
+
var RequestContext = __webpack_require__("i");
|
|
4705
2784
|
;// CONCATENATED MODULE: ./src/logger/StructuredLogger.ts
|
|
4706
2785
|
/**
|
|
4707
2786
|
* Lightweight structured logging without external dependencies.
|
|
@@ -4959,8 +3038,6 @@ var RequestContext = __webpack_require__("y");
|
|
|
4959
3038
|
|
|
4960
3039
|
// EXTERNAL MODULE: ./src/schema.ts
|
|
4961
3040
|
var schema = __webpack_require__("R");
|
|
4962
|
-
// EXTERNAL MODULE: ./src/transport/SseTransport.ts
|
|
4963
|
-
var transport_SseTransport = __webpack_require__("W");
|
|
4964
3041
|
;// CONCATENATED MODULE: ./src/cli.ts
|
|
4965
3042
|
//#!/usr/bin/env bun
|
|
4966
3043
|
// CLI entry point for tracelattice MCP server.
|
|
@@ -4977,16 +3054,11 @@ var transport_SseTransport = __webpack_require__("W");
|
|
|
4977
3054
|
|
|
4978
3055
|
|
|
4979
3056
|
|
|
4980
|
-
|
|
4981
|
-
|
|
4982
|
-
|
|
4983
|
-
|
|
4984
|
-
|
|
4985
3057
|
// Get version from package.json
|
|
4986
3058
|
const CLI_NAME = 'tracelattice';
|
|
4987
|
-
const cli_filename = (0,
|
|
4988
|
-
const cli_dirname = dirname(cli_filename);
|
|
4989
|
-
const package_json = JSON.parse(readFileSync(join(cli_dirname, '../package.json'), 'utf-8'));
|
|
3059
|
+
const cli_filename = (0,__rspack_external_node_url_3991086a.fileURLToPath)(import.meta.url);
|
|
3060
|
+
const cli_dirname = (0,__rspack_external_node_path_806ed179.dirname)(cli_filename);
|
|
3061
|
+
const package_json = JSON.parse((0,__rspack_external_node_fs_1b05aee1.readFileSync)((0,__rspack_external_node_path_806ed179.join)(cli_dirname, '../package.json'), 'utf-8'));
|
|
4990
3062
|
const { version } = package_json;
|
|
4991
3063
|
// Handle CLI arguments
|
|
4992
3064
|
const args = process.argv.slice(2);
|
|
@@ -4997,14 +3069,8 @@ if (shouldShowVersion) {
|
|
|
4997
3069
|
}
|
|
4998
3070
|
async function main() {
|
|
4999
3071
|
const transportType = process.env.TRANSPORT_TYPE || 'stdio';
|
|
5000
|
-
|
|
5001
|
-
|
|
5002
|
-
const fileConfig = configLoader.load();
|
|
5003
|
-
const effectiveConfig = new ServerConfig(configLoader.toServerConfigOptions(fileConfig ?? {}));
|
|
5004
|
-
(0,transport_SseTransport/* .assertPooledSsePersistence */.c)(true, effectiveConfig.persistence);
|
|
5005
|
-
}
|
|
5006
|
-
const adapter = new ValibotJsonSchemaAdapter();
|
|
5007
|
-
const server = new McpServer({
|
|
3072
|
+
const adapter = new __rspack_external__tmcp_adapter_valibot_0faddfa6.ValibotJsonSchemaAdapter();
|
|
3073
|
+
const server = new __rspack_external_tmcp.McpServer({
|
|
5008
3074
|
name: CLI_NAME,
|
|
5009
3075
|
version,
|
|
5010
3076
|
description: 'Semantic Sequential Thinking MCP Server'
|
|
@@ -5016,88 +3082,30 @@ async function main() {
|
|
|
5016
3082
|
}
|
|
5017
3083
|
}
|
|
5018
3084
|
});
|
|
5019
|
-
const thinkingServer = await (0,
|
|
3085
|
+
const thinkingServer = await (0,__rspack_external__lib_js_1645bc55.initializeServer)();
|
|
5020
3086
|
const lifecycle = new CliLifecycle(thinkingServer);
|
|
5021
3087
|
try {
|
|
5022
|
-
|
|
5023
|
-
|
|
3088
|
+
server.tool({
|
|
3089
|
+
name: 'sequentialthinking_tools',
|
|
3090
|
+
description: schema/* .SEQUENTIAL_THINKING_TOOL.description */.iV.description,
|
|
3091
|
+
schema: schema/* .SequentialThinkingSchema */.ZK
|
|
3092
|
+
}, async (input)=>thinkingServer.processThought(input));
|
|
3093
|
+
if (transportType === 'streamable-http') {
|
|
3094
|
+
await startStreamableHttpTransport(server, thinkingServer, lifecycle);
|
|
5024
3095
|
} else {
|
|
5025
|
-
server
|
|
5026
|
-
name: 'sequentialthinking_tools',
|
|
5027
|
-
description: schema/* .SEQUENTIAL_THINKING_TOOL.description */.iV.description,
|
|
5028
|
-
schema: schema/* .SequentialThinkingSchema */.ZK
|
|
5029
|
-
}, async (input)=>thinkingServer.processThought(input));
|
|
5030
|
-
if (transportType === 'streamable-http') {
|
|
5031
|
-
await startStreamableHttpTransport(server, thinkingServer, lifecycle);
|
|
5032
|
-
} else {
|
|
5033
|
-
await startStdioTransport(server, thinkingServer, lifecycle);
|
|
5034
|
-
}
|
|
3096
|
+
await startStdioTransport(server, thinkingServer, lifecycle);
|
|
5035
3097
|
}
|
|
5036
3098
|
registerShutdownHandlers(lifecycle, thinkingServer, transportType === 'stdio');
|
|
5037
3099
|
} catch (error) {
|
|
5038
3100
|
await lifecycle.rollbackStartup(error);
|
|
5039
3101
|
}
|
|
5040
3102
|
}
|
|
5041
|
-
/**
|
|
5042
|
-
* Start SSE transport for multi-user support
|
|
5043
|
-
*/ async function startSseTransport(server, thinkingServer, lifecycle) {
|
|
5044
|
-
const { SseTransport } = await Promise.resolve(/* import() */).then(__webpack_require__.bind(__webpack_require__, "W"));
|
|
5045
|
-
const { createConnectionPool } = await Promise.resolve(/* import() */).then(__webpack_require__.bind(__webpack_require__, "v"));
|
|
5046
|
-
const port = parseInt(process.env.SSE_PORT || '3000', 10);
|
|
5047
|
-
const host = process.env.SSE_HOST || 'localhost';
|
|
5048
|
-
const transportMetrics = thinkingServer.getContainer().resolve('Metrics');
|
|
5049
|
-
const enablePool = process.env.SSE_ENABLE_POOL !== 'false';
|
|
5050
|
-
const maxSessions = parseInt(process.env.SSE_MAX_SESSIONS || '100', 10);
|
|
5051
|
-
const sessionTimeout = parseInt(process.env.SSE_SESSION_TIMEOUT || '300000', 10);
|
|
5052
|
-
const connectionPool = enablePool ? createConnectionPool({
|
|
5053
|
-
maxSessions,
|
|
5054
|
-
sessionTimeout,
|
|
5055
|
-
logger: thinkingServer['_logger'],
|
|
5056
|
-
serverFactory: async ()=>{
|
|
5057
|
-
const { createServer: createThinkingServer } = await Promise.resolve(/* import() */).then(__webpack_require__.bind(__webpack_require__, "r"));
|
|
5058
|
-
const sessionServer = await createThinkingServer({
|
|
5059
|
-
autoDiscover: true
|
|
5060
|
-
});
|
|
5061
|
-
return sessionServer;
|
|
5062
|
-
}
|
|
5063
|
-
}) : undefined;
|
|
5064
|
-
const sseTransport = new SseTransport({
|
|
5065
|
-
port,
|
|
5066
|
-
host,
|
|
5067
|
-
corsOrigin: process.env.CORS_ORIGIN || '*',
|
|
5068
|
-
enableCors: process.env.ENABLE_CORS !== 'false',
|
|
5069
|
-
allowedHosts: process.env.ALLOWED_HOSTS?.split(',').map((hostValue)=>hostValue.trim()),
|
|
5070
|
-
metrics: transportMetrics,
|
|
5071
|
-
connectionPool,
|
|
5072
|
-
persistence: thinkingServer.config.persistence
|
|
5073
|
-
});
|
|
5074
|
-
lifecycle.attachTransport(sseTransport);
|
|
5075
|
-
server.tool({
|
|
5076
|
-
name: 'sequentialthinking_tools',
|
|
5077
|
-
description: schema/* .SEQUENTIAL_THINKING_TOOL.description */.iV.description,
|
|
5078
|
-
schema: schema/* .SequentialThinkingSchema */.ZK
|
|
5079
|
-
}, async (input)=>{
|
|
5080
|
-
if (!connectionPool) {
|
|
5081
|
-
return thinkingServer.processThought(input);
|
|
5082
|
-
}
|
|
5083
|
-
const result = await connectionPool.process((0,ids/* .asSessionId */.Kd)((0,RequestContext/* .getOwner */.QQ)() ?? ''), input);
|
|
5084
|
-
return {
|
|
5085
|
-
content: result.content,
|
|
5086
|
-
...result.isError === undefined ? {} : {
|
|
5087
|
-
isError: result.isError
|
|
5088
|
-
}
|
|
5089
|
-
};
|
|
5090
|
-
});
|
|
5091
|
-
// Connect the SSE transport
|
|
5092
|
-
await sseTransport.connect(server);
|
|
5093
|
-
thinkingServer['_logger'].info(`Sequential Thinking MCP Server running on SSE transport at http://${host}:${port}`);
|
|
5094
|
-
}
|
|
5095
3103
|
/**
|
|
5096
3104
|
* Start Streamable HTTP transport (MCP spec recommended)
|
|
5097
3105
|
*/ async function startStreamableHttpTransport(server, thinkingServer, lifecycle) {
|
|
5098
|
-
const { StreamableHttpTransport } = await Promise.resolve(/* import() */).then(__webpack_require__.bind(__webpack_require__, "
|
|
5099
|
-
const port = parseInt(process.env.STREAMABLE_HTTP_PORT ||
|
|
5100
|
-
const host = process.env.STREAMABLE_HTTP_HOST ||
|
|
3106
|
+
const { StreamableHttpTransport } = await Promise.resolve(/* import() */).then(__webpack_require__.bind(__webpack_require__, "E"));
|
|
3107
|
+
const port = parseInt(process.env.STREAMABLE_HTTP_PORT || '9007', 10);
|
|
3108
|
+
const host = process.env.STREAMABLE_HTTP_HOST || 'localhost';
|
|
5101
3109
|
const transportMetrics = thinkingServer.getContainer().resolve('Metrics');
|
|
5102
3110
|
const stateful = process.env.STREAMABLE_HTTP_STATEFUL !== 'false';
|
|
5103
3111
|
const streamableTransport = new StreamableHttpTransport({
|
|
@@ -5117,7 +3125,7 @@ async function main() {
|
|
|
5117
3125
|
/**
|
|
5118
3126
|
* Start stdio transport (default, single-user)
|
|
5119
3127
|
*/ async function startStdioTransport(server, thinkingServer, lifecycle) {
|
|
5120
|
-
const transport = new StdioTransport(server);
|
|
3128
|
+
const transport = new __rspack_external__tmcp_transport_stdio_98e5584f.StdioTransport(server);
|
|
5121
3129
|
const processListeners = {
|
|
5122
3130
|
sigint: new Set(process.listeners('SIGINT')),
|
|
5123
3131
|
sigterm: new Set(process.listeners('SIGTERM')),
|