@sundaeswap/sprinkles 0.6.0 → 0.7.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (158) hide show
  1. package/dist/cjs/Sprinkle/__tests__/action-integration.test.js +590 -0
  2. package/dist/cjs/Sprinkle/__tests__/action-integration.test.js.map +1 -0
  3. package/dist/cjs/Sprinkle/__tests__/action-registry.test.js +193 -0
  4. package/dist/cjs/Sprinkle/__tests__/action-registry.test.js.map +1 -0
  5. package/dist/cjs/Sprinkle/__tests__/action-runner.test.js +304 -0
  6. package/dist/cjs/Sprinkle/__tests__/action-runner.test.js.map +1 -0
  7. package/dist/cjs/Sprinkle/__tests__/builtin-actions.test.js +1110 -0
  8. package/dist/cjs/Sprinkle/__tests__/builtin-actions.test.js.map +1 -0
  9. package/dist/cjs/Sprinkle/__tests__/cli-adapter.test.js +722 -0
  10. package/dist/cjs/Sprinkle/__tests__/cli-adapter.test.js.map +1 -0
  11. package/dist/cjs/Sprinkle/__tests__/fill-in-struct.test.js +138 -0
  12. package/dist/cjs/Sprinkle/__tests__/fill-in-struct.test.js.map +1 -1
  13. package/dist/cjs/Sprinkle/__tests__/mcp-adapter.test.js +713 -0
  14. package/dist/cjs/Sprinkle/__tests__/mcp-adapter.test.js.map +1 -0
  15. package/dist/cjs/Sprinkle/__tests__/tui-helpers.test.js +334 -0
  16. package/dist/cjs/Sprinkle/__tests__/tui-helpers.test.js.map +1 -0
  17. package/dist/cjs/Sprinkle/__tests__/wallet-transaction-actions.test.js +749 -0
  18. package/dist/cjs/Sprinkle/__tests__/wallet-transaction-actions.test.js.map +1 -0
  19. package/dist/cjs/Sprinkle/actions/builtin/blaze-helper.js +61 -0
  20. package/dist/cjs/Sprinkle/actions/builtin/blaze-helper.js.map +1 -0
  21. package/dist/cjs/Sprinkle/actions/builtin/index.js +117 -0
  22. package/dist/cjs/Sprinkle/actions/builtin/index.js.map +1 -0
  23. package/dist/cjs/Sprinkle/actions/builtin/profile-actions.js +202 -0
  24. package/dist/cjs/Sprinkle/actions/builtin/profile-actions.js.map +1 -0
  25. package/dist/cjs/Sprinkle/actions/builtin/settings-actions.js +87 -0
  26. package/dist/cjs/Sprinkle/actions/builtin/settings-actions.js.map +1 -0
  27. package/dist/cjs/Sprinkle/actions/builtin/transaction-actions.js +345 -0
  28. package/dist/cjs/Sprinkle/actions/builtin/transaction-actions.js.map +1 -0
  29. package/dist/cjs/Sprinkle/actions/builtin/wallet-actions.js +212 -0
  30. package/dist/cjs/Sprinkle/actions/builtin/wallet-actions.js.map +1 -0
  31. package/dist/cjs/Sprinkle/actions/cli-adapter.js +372 -0
  32. package/dist/cjs/Sprinkle/actions/cli-adapter.js.map +1 -0
  33. package/dist/cjs/Sprinkle/actions/index.js +127 -0
  34. package/dist/cjs/Sprinkle/actions/index.js.map +1 -0
  35. package/dist/cjs/Sprinkle/actions/mcp-adapter.js +415 -0
  36. package/dist/cjs/Sprinkle/actions/mcp-adapter.js.map +1 -0
  37. package/dist/cjs/Sprinkle/actions/registry.js +92 -0
  38. package/dist/cjs/Sprinkle/actions/registry.js.map +1 -0
  39. package/dist/cjs/Sprinkle/actions/runner.js +190 -0
  40. package/dist/cjs/Sprinkle/actions/runner.js.map +1 -0
  41. package/dist/cjs/Sprinkle/actions/tui-helpers.js +96 -0
  42. package/dist/cjs/Sprinkle/actions/tui-helpers.js.map +1 -0
  43. package/dist/cjs/Sprinkle/actions/types.js +68 -0
  44. package/dist/cjs/Sprinkle/actions/types.js.map +1 -0
  45. package/dist/cjs/Sprinkle/index.js +451 -4
  46. package/dist/cjs/Sprinkle/index.js.map +1 -1
  47. package/dist/cjs/Sprinkle/prompts.js +12 -7
  48. package/dist/cjs/Sprinkle/prompts.js.map +1 -1
  49. package/dist/cjs/Sprinkle/type-guards.js +7 -1
  50. package/dist/cjs/Sprinkle/type-guards.js.map +1 -1
  51. package/dist/esm/Sprinkle/__tests__/action-integration.test.js +588 -0
  52. package/dist/esm/Sprinkle/__tests__/action-integration.test.js.map +1 -0
  53. package/dist/esm/Sprinkle/__tests__/action-registry.test.js +192 -0
  54. package/dist/esm/Sprinkle/__tests__/action-registry.test.js.map +1 -0
  55. package/dist/esm/Sprinkle/__tests__/action-runner.test.js +302 -0
  56. package/dist/esm/Sprinkle/__tests__/action-runner.test.js.map +1 -0
  57. package/dist/esm/Sprinkle/__tests__/builtin-actions.test.js +1107 -0
  58. package/dist/esm/Sprinkle/__tests__/builtin-actions.test.js.map +1 -0
  59. package/dist/esm/Sprinkle/__tests__/cli-adapter.test.js +720 -0
  60. package/dist/esm/Sprinkle/__tests__/cli-adapter.test.js.map +1 -0
  61. package/dist/esm/Sprinkle/__tests__/fill-in-struct.test.js +138 -0
  62. package/dist/esm/Sprinkle/__tests__/fill-in-struct.test.js.map +1 -1
  63. package/dist/esm/Sprinkle/__tests__/mcp-adapter.test.js +712 -0
  64. package/dist/esm/Sprinkle/__tests__/mcp-adapter.test.js.map +1 -0
  65. package/dist/esm/Sprinkle/__tests__/tui-helpers.test.js +332 -0
  66. package/dist/esm/Sprinkle/__tests__/tui-helpers.test.js.map +1 -0
  67. package/dist/esm/Sprinkle/__tests__/wallet-transaction-actions.test.js +747 -0
  68. package/dist/esm/Sprinkle/__tests__/wallet-transaction-actions.test.js.map +1 -0
  69. package/dist/esm/Sprinkle/actions/builtin/blaze-helper.js +55 -0
  70. package/dist/esm/Sprinkle/actions/builtin/blaze-helper.js.map +1 -0
  71. package/dist/esm/Sprinkle/actions/builtin/index.js +32 -0
  72. package/dist/esm/Sprinkle/actions/builtin/index.js.map +1 -0
  73. package/dist/esm/Sprinkle/actions/builtin/profile-actions.js +197 -0
  74. package/dist/esm/Sprinkle/actions/builtin/profile-actions.js.map +1 -0
  75. package/dist/esm/Sprinkle/actions/builtin/settings-actions.js +81 -0
  76. package/dist/esm/Sprinkle/actions/builtin/settings-actions.js.map +1 -0
  77. package/dist/esm/Sprinkle/actions/builtin/transaction-actions.js +340 -0
  78. package/dist/esm/Sprinkle/actions/builtin/transaction-actions.js.map +1 -0
  79. package/dist/esm/Sprinkle/actions/builtin/wallet-actions.js +207 -0
  80. package/dist/esm/Sprinkle/actions/builtin/wallet-actions.js.map +1 -0
  81. package/dist/esm/Sprinkle/actions/cli-adapter.js +361 -0
  82. package/dist/esm/Sprinkle/actions/cli-adapter.js.map +1 -0
  83. package/dist/esm/Sprinkle/actions/index.js +12 -0
  84. package/dist/esm/Sprinkle/actions/index.js.map +1 -0
  85. package/dist/esm/Sprinkle/actions/mcp-adapter.js +407 -0
  86. package/dist/esm/Sprinkle/actions/mcp-adapter.js.map +1 -0
  87. package/dist/esm/Sprinkle/actions/registry.js +85 -0
  88. package/dist/esm/Sprinkle/actions/registry.js.map +1 -0
  89. package/dist/esm/Sprinkle/actions/runner.js +182 -0
  90. package/dist/esm/Sprinkle/actions/runner.js.map +1 -0
  91. package/dist/esm/Sprinkle/actions/tui-helpers.js +91 -0
  92. package/dist/esm/Sprinkle/actions/tui-helpers.js.map +1 -0
  93. package/dist/esm/Sprinkle/actions/types.js +61 -0
  94. package/dist/esm/Sprinkle/actions/types.js.map +1 -0
  95. package/dist/esm/Sprinkle/index.js +299 -4
  96. package/dist/esm/Sprinkle/index.js.map +1 -1
  97. package/dist/esm/Sprinkle/prompts.js +12 -7
  98. package/dist/esm/Sprinkle/prompts.js.map +1 -1
  99. package/dist/esm/Sprinkle/type-guards.js +3 -0
  100. package/dist/esm/Sprinkle/type-guards.js.map +1 -1
  101. package/dist/types/Sprinkle/actions/builtin/blaze-helper.d.ts +39 -0
  102. package/dist/types/Sprinkle/actions/builtin/blaze-helper.d.ts.map +1 -0
  103. package/dist/types/Sprinkle/actions/builtin/index.d.ts +26 -0
  104. package/dist/types/Sprinkle/actions/builtin/index.d.ts.map +1 -0
  105. package/dist/types/Sprinkle/actions/builtin/profile-actions.d.ts +55 -0
  106. package/dist/types/Sprinkle/actions/builtin/profile-actions.d.ts.map +1 -0
  107. package/dist/types/Sprinkle/actions/builtin/settings-actions.d.ts +32 -0
  108. package/dist/types/Sprinkle/actions/builtin/settings-actions.d.ts.map +1 -0
  109. package/dist/types/Sprinkle/actions/builtin/transaction-actions.d.ts +70 -0
  110. package/dist/types/Sprinkle/actions/builtin/transaction-actions.d.ts.map +1 -0
  111. package/dist/types/Sprinkle/actions/builtin/wallet-actions.d.ts +50 -0
  112. package/dist/types/Sprinkle/actions/builtin/wallet-actions.d.ts.map +1 -0
  113. package/dist/types/Sprinkle/actions/cli-adapter.d.ts +104 -0
  114. package/dist/types/Sprinkle/actions/cli-adapter.d.ts.map +1 -0
  115. package/dist/types/Sprinkle/actions/index.d.ts +12 -0
  116. package/dist/types/Sprinkle/actions/index.d.ts.map +1 -0
  117. package/dist/types/Sprinkle/actions/mcp-adapter.d.ts +92 -0
  118. package/dist/types/Sprinkle/actions/mcp-adapter.d.ts.map +1 -0
  119. package/dist/types/Sprinkle/actions/registry.d.ts +42 -0
  120. package/dist/types/Sprinkle/actions/registry.d.ts.map +1 -0
  121. package/dist/types/Sprinkle/actions/runner.d.ts +45 -0
  122. package/dist/types/Sprinkle/actions/runner.d.ts.map +1 -0
  123. package/dist/types/Sprinkle/actions/tui-helpers.d.ts +53 -0
  124. package/dist/types/Sprinkle/actions/tui-helpers.d.ts.map +1 -0
  125. package/dist/types/Sprinkle/actions/types.d.ts +76 -0
  126. package/dist/types/Sprinkle/actions/types.d.ts.map +1 -0
  127. package/dist/types/Sprinkle/index.d.ts +81 -1
  128. package/dist/types/Sprinkle/index.d.ts.map +1 -1
  129. package/dist/types/Sprinkle/prompts.d.ts.map +1 -1
  130. package/dist/types/Sprinkle/type-guards.d.ts +4 -1
  131. package/dist/types/Sprinkle/type-guards.d.ts.map +1 -1
  132. package/dist/types/tsconfig.build.tsbuildinfo +1 -1
  133. package/package.json +9 -2
  134. package/src/Sprinkle/__tests__/action-integration.test.ts +558 -0
  135. package/src/Sprinkle/__tests__/action-registry.test.ts +187 -0
  136. package/src/Sprinkle/__tests__/action-runner.test.ts +324 -0
  137. package/src/Sprinkle/__tests__/builtin-actions.test.ts +1022 -0
  138. package/src/Sprinkle/__tests__/cli-adapter.test.ts +715 -0
  139. package/src/Sprinkle/__tests__/fill-in-struct.test.ts +144 -0
  140. package/src/Sprinkle/__tests__/mcp-adapter.test.ts +718 -0
  141. package/src/Sprinkle/__tests__/tui-helpers.test.ts +325 -0
  142. package/src/Sprinkle/__tests__/wallet-transaction-actions.test.ts +695 -0
  143. package/src/Sprinkle/actions/builtin/blaze-helper.ts +89 -0
  144. package/src/Sprinkle/actions/builtin/index.ts +86 -0
  145. package/src/Sprinkle/actions/builtin/profile-actions.ts +229 -0
  146. package/src/Sprinkle/actions/builtin/settings-actions.ts +99 -0
  147. package/src/Sprinkle/actions/builtin/transaction-actions.ts +381 -0
  148. package/src/Sprinkle/actions/builtin/wallet-actions.ts +233 -0
  149. package/src/Sprinkle/actions/cli-adapter.ts +430 -0
  150. package/src/Sprinkle/actions/index.ts +32 -0
  151. package/src/Sprinkle/actions/mcp-adapter.ts +463 -0
  152. package/src/Sprinkle/actions/registry.ts +97 -0
  153. package/src/Sprinkle/actions/runner.ts +200 -0
  154. package/src/Sprinkle/actions/tui-helpers.ts +114 -0
  155. package/src/Sprinkle/actions/types.ts +91 -0
  156. package/src/Sprinkle/index.ts +395 -3
  157. package/src/Sprinkle/prompts.ts +118 -72
  158. package/src/Sprinkle/type-guards.ts +9 -0
@@ -0,0 +1,415 @@
1
+ "use strict";
2
+
3
+ Object.defineProperty(exports, "__esModule", {
4
+ value: true
5
+ });
6
+ exports.coerceMcpInput = coerceMcpInput;
7
+ exports.createMcpServer = createMcpServer;
8
+ exports.getMcpSdk = getMcpSdk;
9
+ exports.runMcp = runMcp;
10
+ exports.typeboxToJsonSchema = typeboxToJsonSchema;
11
+ var _module = require("module");
12
+ var _url = require("url");
13
+ var _path = require("path");
14
+ var _encryption = require("../encryption.js");
15
+ var _typeGuards = require("../type-guards.js");
16
+ var _runner = require("./runner.js");
17
+ function _interopRequireWildcard(e, t) { if ("function" == typeof WeakMap) var r = new WeakMap(), n = new WeakMap(); return (_interopRequireWildcard = function (e, t) { if (!t && e && e.__esModule) return e; var o, i, f = { __proto__: null, default: e }; if (null === e || "object" != typeof e && "function" != typeof e) return f; if (o = t ? n : r) { if (o.has(e)) return o.get(e); o.set(e, f); } for (const t in e) "default" !== t && {}.hasOwnProperty.call(e, t) && ((i = (o = Object.defineProperty) && Object.getOwnPropertyDescriptor(e, t)) && (i.get || i.set) ? o(f, t, i) : f[t] = e[t]); return f; })(e, t); } /**
18
+ * MCP adapter for Sprinkles actions.
19
+ *
20
+ * Provides:
21
+ * - TypeBox to JSON Schema conversion (typeboxToJsonSchema)
22
+ * - BigInt string coercion for MCP input (coerceMcpInput)
23
+ * - Lazy MCP SDK import with graceful error (getMcpSdk)
24
+ * - MCP server creation from registered actions (createMcpServer)
25
+ * - MCP orchestrator that starts a stdio server (runMcp)
26
+ */
27
+ // Re-import Sprinkle as a type only to avoid circular deps
28
+
29
+ // Load package version for MCP server identification
30
+ // Robustly find package.json - works from both src and dist directories
31
+ function loadPackageVersion() {
32
+ const require = (0, _module.createRequire)(import.meta.url);
33
+ const __filename = (0, _url.fileURLToPath)(import.meta.url);
34
+ const __dirname = (0, _path.dirname)(__filename);
35
+
36
+ // Try multiple possible paths (handles src vs dist/esm vs dist/cjs)
37
+ const candidates = [(0, _path.resolve)(__dirname, "../../../package.json"),
38
+ // from src/Sprinkle/actions
39
+ (0, _path.resolve)(__dirname, "../../../../package.json") // from dist/*/Sprinkle/actions
40
+ ];
41
+ for (const candidate of candidates) {
42
+ try {
43
+ const pkg = require(candidate);
44
+ return pkg.version;
45
+ } catch {
46
+ // Try next candidate
47
+ }
48
+ }
49
+ return "0.0.0"; // Fallback if package.json not found
50
+ }
51
+ const PACKAGE_VERSION = loadPackageVersion();
52
+
53
+ // ---------------------------------------------------------------------------
54
+ // TypeBox to JSON Schema conversion
55
+ // ---------------------------------------------------------------------------
56
+
57
+ /**
58
+ * Convert a TypeBox schema to a plain JSON Schema object.
59
+ *
60
+ * Strips TypeBox-internal symbols and properties (Kind, OptionalKind, $id)
61
+ * and maps TypeBox-specific types to their JSON Schema equivalents:
62
+ * - BigInt -> { type: "string", pattern: "^-?[0-9]+$" } (JSON has no BigInt)
63
+ * - Sensitive string fields -> add writeOnly: true
64
+ * - Optional -> recurse on inner schema (Optional does not change Kind)
65
+ * - Union -> { anyOf: [...] }
66
+ * - Literal -> { type, const }
67
+ * - Null -> { type: "null" }
68
+ * - Unknown/unsupported -> {} (accepts anything)
69
+ */
70
+ function typeboxToJsonSchema(schema) {
71
+ // Optional in TypeBox doesn't change the Kind, but marks the schema with
72
+ // OptionalKind. We can check for it and recurse transparently since all
73
+ // other guards still work correctly on optional-wrapped schemas.
74
+ //
75
+ // We intentionally do NOT strip optional here -- the containing Object
76
+ // converter decides whether to include a property in `required` based
77
+ // on the isOptional guard applied to the property schema.
78
+
79
+ if ((0, _typeGuards.isBigInt)(schema)) {
80
+ return {
81
+ type: "string",
82
+ pattern: "^-?[0-9]+$",
83
+ description: "BigInt value as string"
84
+ };
85
+ }
86
+ if ((0, _typeGuards.isString)(schema)) {
87
+ const result = {
88
+ type: "string"
89
+ };
90
+ if (schema.description !== undefined) result.description = schema.description;
91
+ if (schema.title !== undefined) result.title = schema.title;
92
+ if (schema.examples !== undefined) result.examples = schema.examples;
93
+ if (schema.pattern !== undefined) result.pattern = schema.pattern;
94
+ if (schema.minLength !== undefined) result.minLength = schema.minLength;
95
+ if (schema.maxLength !== undefined) result.maxLength = schema.maxLength;
96
+ if (schema.default !== undefined) result.default = schema.default;
97
+ // Sensitive fields are write-only (never returned in responses)
98
+ if ((0, _typeGuards.isSensitive)(schema)) result.writeOnly = true;
99
+ return result;
100
+ }
101
+ if ((0, _typeGuards.isNumber)(schema)) {
102
+ const result = {
103
+ type: "number"
104
+ };
105
+ if (schema.minimum !== undefined) result.minimum = schema.minimum;
106
+ if (schema.maximum !== undefined) result.maximum = schema.maximum;
107
+ if (schema.description !== undefined) result.description = schema.description;
108
+ if (schema.default !== undefined) result.default = schema.default;
109
+ return result;
110
+ }
111
+ if ((0, _typeGuards.isInteger)(schema)) {
112
+ const result = {
113
+ type: "integer"
114
+ };
115
+ if (schema.minimum !== undefined) result.minimum = schema.minimum;
116
+ if (schema.maximum !== undefined) result.maximum = schema.maximum;
117
+ if (schema.description !== undefined) result.description = schema.description;
118
+ if (schema.default !== undefined) result.default = schema.default;
119
+ return result;
120
+ }
121
+ if ((0, _typeGuards.isBoolean)(schema)) {
122
+ const result = {
123
+ type: "boolean"
124
+ };
125
+ if (schema.description !== undefined) result.description = schema.description;
126
+ if (schema.default !== undefined) result.default = schema.default;
127
+ return result;
128
+ }
129
+ if ((0, _typeGuards.isNull)(schema)) {
130
+ return {
131
+ type: "null"
132
+ };
133
+ }
134
+ if ((0, _typeGuards.isArray)(schema)) {
135
+ const result = {
136
+ type: "array"
137
+ };
138
+ const itemSchema = schema.items;
139
+ if (itemSchema) {
140
+ result.items = typeboxToJsonSchema(itemSchema);
141
+ }
142
+ if (schema.minItems !== undefined) result.minItems = schema.minItems;
143
+ if (schema.maxItems !== undefined) result.maxItems = schema.maxItems;
144
+ if (schema.description !== undefined) result.description = schema.description;
145
+ return result;
146
+ }
147
+ if ((0, _typeGuards.isObject)(schema)) {
148
+ const properties = schema.properties;
149
+ const required = schema.required ?? [];
150
+ const convertedProperties = {};
151
+ for (const [propName, propSchema] of Object.entries(properties)) {
152
+ convertedProperties[propName] = typeboxToJsonSchema(propSchema);
153
+ }
154
+ const result = {
155
+ type: "object",
156
+ properties: convertedProperties
157
+ };
158
+ if (required.length > 0) {
159
+ result.required = required;
160
+ }
161
+ if (schema.description !== undefined) result.description = schema.description;
162
+ return result;
163
+ }
164
+ if ((0, _typeGuards.isUnion)(schema)) {
165
+ return {
166
+ anyOf: schema.anyOf.map(member => typeboxToJsonSchema(member))
167
+ };
168
+ }
169
+ if ((0, _typeGuards.isLiteral)(schema)) {
170
+ const value = schema.const;
171
+ let type;
172
+ if (typeof value === "string") {
173
+ type = "string";
174
+ } else if (typeof value === "number") {
175
+ type = "number";
176
+ } else if (typeof value === "boolean") {
177
+ type = "boolean";
178
+ } else {
179
+ // Fallback for unexpected literal types
180
+ return {};
181
+ }
182
+ return {
183
+ type,
184
+ const: value
185
+ };
186
+ }
187
+
188
+ // Unknown / unsupported TypeBox type: emit empty schema (accepts anything)
189
+ // This is a safe fallback that allows the MCP tool to still receive input.
190
+ console.warn(`[mcp-adapter] Unsupported TypeBox kind: ${schema["[Kind]"] ?? "(unknown)"}. Emitting empty schema.`);
191
+ return {};
192
+ }
193
+
194
+ // ---------------------------------------------------------------------------
195
+ // Input coercion: BigInt string -> BigInt
196
+ // ---------------------------------------------------------------------------
197
+
198
+ /**
199
+ * Coerce MCP JSON input values to the types expected by a TypeBox schema.
200
+ *
201
+ * MCP transmits all values as JSON, which has no BigInt type. When the schema
202
+ * expects a BigInt, the value arrives as a numeric string (e.g. "12345678").
203
+ * This function recursively walks the schema and input, converting BigInt
204
+ * string values to actual BigInt where needed.
205
+ *
206
+ * For all other types the value is passed through unchanged.
207
+ */
208
+ function coerceMcpInput(input, schema) {
209
+ if (input === null || input === undefined) return input;
210
+ if ((0, _typeGuards.isBigInt)(schema)) {
211
+ if (typeof input === "bigint") return input;
212
+ if (typeof input === "string" && /^-?[0-9]+$/.test(input)) {
213
+ try {
214
+ return BigInt(input);
215
+ } catch {
216
+ return input;
217
+ }
218
+ }
219
+ if (typeof input === "number") {
220
+ try {
221
+ return BigInt(Math.trunc(input));
222
+ } catch {
223
+ return input;
224
+ }
225
+ }
226
+ return input;
227
+ }
228
+ if ((0, _typeGuards.isArray)(schema)) {
229
+ const itemSchema = schema.items;
230
+ if (Array.isArray(input) && itemSchema) {
231
+ return input.map(item => coerceMcpInput(item, itemSchema));
232
+ }
233
+ return input;
234
+ }
235
+ if ((0, _typeGuards.isObject)(schema)) {
236
+ if (typeof input !== "object" || Array.isArray(input)) return input;
237
+ const properties = schema.properties;
238
+ const result = {
239
+ ...input
240
+ };
241
+ for (const [propName, propSchema] of Object.entries(properties)) {
242
+ if (propName in result) {
243
+ result[propName] = coerceMcpInput(result[propName], propSchema);
244
+ }
245
+ }
246
+ return result;
247
+ }
248
+ if ((0, _typeGuards.isUnion)(schema)) {
249
+ // For unions, we try each member schema in order and return the first
250
+ // successful coercion. BigInt members take priority over string members
251
+ // since they have a narrower, unambiguous pattern.
252
+ for (const member of schema.anyOf) {
253
+ if ((0, _typeGuards.isBigInt)(member)) {
254
+ if (typeof input === "string" && /^-?[0-9]+$/.test(input)) {
255
+ return coerceMcpInput(input, member);
256
+ }
257
+ }
258
+ }
259
+ // No BigInt match; return as-is for other union members
260
+ return input;
261
+ }
262
+
263
+ // For all other types (String, Number, Integer, Boolean, Literal, Null):
264
+ // pass through unchanged -- MCP JSON already represents them correctly
265
+ return input;
266
+ }
267
+
268
+ // ---------------------------------------------------------------------------
269
+ // Lazy MCP SDK import
270
+ // ---------------------------------------------------------------------------
271
+
272
+ /**
273
+ * MCP SDK module shape (the parts we use from @modelcontextprotocol/sdk).
274
+ * Typed loosely to avoid a hard dependency at compile time.
275
+ */
276
+
277
+ /**
278
+ * Lazily import the MCP SDK server module.
279
+ *
280
+ * Throws a clear, actionable error if the SDK is not installed, rather than
281
+ * a cryptic "Cannot find module" Node error.
282
+ */
283
+ async function getMcpSdk() {
284
+ try {
285
+ return await Promise.resolve().then(() => _interopRequireWildcard(require("@modelcontextprotocol/sdk/server/mcp.js")));
286
+ } catch {
287
+ throw new Error("MCP mode requires @modelcontextprotocol/sdk. Install it with: npm install @modelcontextprotocol/sdk");
288
+ }
289
+ }
290
+
291
+ /**
292
+ * Lazily import the MCP SDK stdio transport module.
293
+ */
294
+ async function getMcpStdioTransport() {
295
+ try {
296
+ return await Promise.resolve().then(() => _interopRequireWildcard(require("@modelcontextprotocol/sdk/server/stdio.js")));
297
+ } catch {
298
+ throw new Error("MCP mode requires @modelcontextprotocol/sdk. Install it with: npm install @modelcontextprotocol/sdk");
299
+ }
300
+ }
301
+
302
+ // ---------------------------------------------------------------------------
303
+ // MCP server creation
304
+ // ---------------------------------------------------------------------------
305
+
306
+ /**
307
+ * Create an MCP server and register all actions from a Sprinkle instance as
308
+ * MCP tools.
309
+ *
310
+ * Each action becomes a tool with:
311
+ * - name: action.name
312
+ * - description: action.description
313
+ * - input schema: typeboxToJsonSchema(action.inputSchema)
314
+ * - handler: coerces input, executes action, returns JSON result
315
+ *
316
+ * The Sprinkle instance must already be initialized with a profile before
317
+ * this function is called.
318
+ *
319
+ * @param sprinkle - Fully-initialized Sprinkle instance
320
+ * @param serverName - Name to use for the MCP server
321
+ * @returns The configured McpServer instance (not yet connected)
322
+ */
323
+ async function createMcpServer(sprinkle, serverName
324
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
325
+ ) {
326
+ const {
327
+ McpServer
328
+ } = await getMcpSdk();
329
+
330
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
331
+ const server = new McpServer({
332
+ name: serverName,
333
+ version: PACKAGE_VERSION
334
+ });
335
+ const actions = sprinkle.listActions();
336
+ for (const action of actions) {
337
+ const inputSchema = typeboxToJsonSchema(action.inputSchema);
338
+
339
+ // Register the action as an MCP tool.
340
+ // The high-level McpServer.tool() API accepts:
341
+ // tool(name, description, schema, handler)
342
+ server.tool(action.name, action.description, inputSchema,
343
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
344
+ async input => {
345
+ const coercedInput = coerceMcpInput(input, action.inputSchema);
346
+ const context = {
347
+ sprinkle,
348
+ settings: sprinkle.settings
349
+ };
350
+
351
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
352
+ const result = await (0, _runner.executeAction)(action, coercedInput, context);
353
+ if (result.success) {
354
+ return {
355
+ content: [{
356
+ type: "text",
357
+ text: JSON.stringify(result.data, _encryption.bigIntReplacer)
358
+ }]
359
+ };
360
+ } else {
361
+ return {
362
+ content: [{
363
+ type: "text",
364
+ text: JSON.stringify({
365
+ error: {
366
+ code: result.error.code,
367
+ message: result.error.message,
368
+ details: result.error.details
369
+ }
370
+ }, _encryption.bigIntReplacer)
371
+ }],
372
+ isError: true
373
+ };
374
+ }
375
+ });
376
+ }
377
+ return server;
378
+ }
379
+
380
+ // ---------------------------------------------------------------------------
381
+ // MCP orchestrator
382
+ // ---------------------------------------------------------------------------
383
+
384
+ /**
385
+ * Start an MCP server on stdio transport.
386
+ *
387
+ * This function:
388
+ * 1. Creates the MCP server and registers all actions as tools
389
+ * 2. Creates a StdioServerTransport
390
+ * 3. Connects the server to the transport
391
+ *
392
+ * IMPORTANT: All logging in this function goes to stderr. stdout is reserved
393
+ * for the MCP protocol messages.
394
+ *
395
+ * The Sprinkle instance must already be initialized with a profile. Profile
396
+ * initialization is the responsibility of the caller (Sprinkle.Run()).
397
+ *
398
+ * @param sprinkle - Fully-initialized Sprinkle instance
399
+ * @param serverName - Name to use for the MCP server
400
+ */
401
+ async function runMcp(sprinkle, serverName) {
402
+ const {
403
+ StdioServerTransport
404
+ } = await getMcpStdioTransport();
405
+ const server = await createMcpServer(sprinkle, serverName);
406
+ const transport = new StdioServerTransport();
407
+ try {
408
+ await server.connect(transport);
409
+ } catch (err) {
410
+ // Log errors to stderr only -- stdout is the MCP transport channel
411
+ process.stderr.write(`[sprinkle-mcp] Failed to start MCP server: ${err instanceof Error ? err.message : String(err)}\n`);
412
+ throw err;
413
+ }
414
+ }
415
+ //# sourceMappingURL=mcp-adapter.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"mcp-adapter.js","names":["_module","require","_url","_path","_encryption","_typeGuards","_runner","_interopRequireWildcard","e","t","WeakMap","r","n","__esModule","o","i","f","__proto__","default","has","get","set","hasOwnProperty","call","Object","defineProperty","getOwnPropertyDescriptor","loadPackageVersion","createRequire","import","meta","url","__filename","fileURLToPath","__dirname","dirname","candidates","resolve","candidate","pkg","version","PACKAGE_VERSION","typeboxToJsonSchema","schema","isBigInt","type","pattern","description","isString","result","undefined","title","examples","minLength","maxLength","isSensitive","writeOnly","isNumber","minimum","maximum","isInteger","isBoolean","isNull","isArray","itemSchema","items","minItems","maxItems","isObject","properties","required","convertedProperties","propName","propSchema","entries","length","isUnion","anyOf","map","member","isLiteral","value","const","console","warn","coerceMcpInput","input","test","BigInt","Math","trunc","Array","item","getMcpSdk","Promise","then","Error","getMcpStdioTransport","createMcpServer","sprinkle","serverName","McpServer","server","name","actions","listActions","action","inputSchema","tool","coercedInput","context","settings","executeAction","success","content","text","JSON","stringify","data","bigIntReplacer","error","code","message","details","isError","runMcp","StdioServerTransport","transport","connect","err","process","stderr","write","String"],"sources":["../../../../src/Sprinkle/actions/mcp-adapter.ts"],"sourcesContent":["/**\n * MCP adapter for Sprinkles actions.\n *\n * Provides:\n * - TypeBox to JSON Schema conversion (typeboxToJsonSchema)\n * - BigInt string coercion for MCP input (coerceMcpInput)\n * - Lazy MCP SDK import with graceful error (getMcpSdk)\n * - MCP server creation from registered actions (createMcpServer)\n * - MCP orchestrator that starts a stdio server (runMcp)\n */\n\nimport { createRequire } from \"module\";\nimport { fileURLToPath } from \"url\";\nimport { dirname, resolve } from \"path\";\nimport type { TSchema } from \"@sinclair/typebox\";\nimport { bigIntReplacer } from \"../encryption.js\";\nimport {\n isArray,\n isBigInt,\n isBoolean,\n isInteger,\n isLiteral,\n isNull,\n isNumber,\n isObject,\n isOptional,\n isString,\n isUnion,\n isSensitive,\n} from \"../type-guards.js\";\nimport type { AnyAction } from \"./types.js\";\nimport { executeAction } from \"./runner.js\";\n\n// Re-import Sprinkle as a type only to avoid circular deps\nimport type { Sprinkle } from \"../index.js\";\n\n// Load package version for MCP server identification\n// Robustly find package.json - works from both src and dist directories\nfunction loadPackageVersion(): string {\n const require = createRequire(import.meta.url);\n const __filename = fileURLToPath(import.meta.url);\n const __dirname = dirname(__filename);\n \n // Try multiple possible paths (handles src vs dist/esm vs dist/cjs)\n const candidates = [\n resolve(__dirname, \"../../../package.json\"), // from src/Sprinkle/actions\n resolve(__dirname, \"../../../../package.json\"), // from dist/*/Sprinkle/actions\n ];\n \n for (const candidate of candidates) {\n try {\n const pkg = require(candidate) as { version: string };\n return pkg.version;\n } catch {\n // Try next candidate\n }\n }\n \n return \"0.0.0\"; // Fallback if package.json not found\n}\n\nconst PACKAGE_VERSION: string = loadPackageVersion();\n\n// ---------------------------------------------------------------------------\n// TypeBox to JSON Schema conversion\n// ---------------------------------------------------------------------------\n\n/**\n * Convert a TypeBox schema to a plain JSON Schema object.\n *\n * Strips TypeBox-internal symbols and properties (Kind, OptionalKind, $id)\n * and maps TypeBox-specific types to their JSON Schema equivalents:\n * - BigInt -> { type: \"string\", pattern: \"^-?[0-9]+$\" } (JSON has no BigInt)\n * - Sensitive string fields -> add writeOnly: true\n * - Optional -> recurse on inner schema (Optional does not change Kind)\n * - Union -> { anyOf: [...] }\n * - Literal -> { type, const }\n * - Null -> { type: \"null\" }\n * - Unknown/unsupported -> {} (accepts anything)\n */\nexport function typeboxToJsonSchema(schema: TSchema): Record<string, unknown> {\n // Optional in TypeBox doesn't change the Kind, but marks the schema with\n // OptionalKind. We can check for it and recurse transparently since all\n // other guards still work correctly on optional-wrapped schemas.\n //\n // We intentionally do NOT strip optional here -- the containing Object\n // converter decides whether to include a property in `required` based\n // on the isOptional guard applied to the property schema.\n\n if (isBigInt(schema)) {\n return {\n type: \"string\",\n pattern: \"^-?[0-9]+$\",\n description: \"BigInt value as string\",\n };\n }\n\n if (isString(schema)) {\n const result: Record<string, unknown> = { type: \"string\" };\n if (schema.description !== undefined) result.description = schema.description;\n if (schema.title !== undefined) result.title = schema.title;\n if (schema.examples !== undefined) result.examples = schema.examples;\n if (schema.pattern !== undefined) result.pattern = schema.pattern;\n if (schema.minLength !== undefined) result.minLength = schema.minLength;\n if (schema.maxLength !== undefined) result.maxLength = schema.maxLength;\n if (schema.default !== undefined) result.default = schema.default;\n // Sensitive fields are write-only (never returned in responses)\n if (isSensitive(schema)) result.writeOnly = true;\n return result;\n }\n\n if (isNumber(schema)) {\n const result: Record<string, unknown> = { type: \"number\" };\n if (schema.minimum !== undefined) result.minimum = schema.minimum;\n if (schema.maximum !== undefined) result.maximum = schema.maximum;\n if (schema.description !== undefined) result.description = schema.description;\n if (schema.default !== undefined) result.default = schema.default;\n return result;\n }\n\n if (isInteger(schema)) {\n const result: Record<string, unknown> = { type: \"integer\" };\n if (schema.minimum !== undefined) result.minimum = schema.minimum;\n if (schema.maximum !== undefined) result.maximum = schema.maximum;\n if (schema.description !== undefined) result.description = schema.description;\n if (schema.default !== undefined) result.default = schema.default;\n return result;\n }\n\n if (isBoolean(schema)) {\n const result: Record<string, unknown> = { type: \"boolean\" };\n if (schema.description !== undefined) result.description = schema.description;\n if (schema.default !== undefined) result.default = schema.default;\n return result;\n }\n\n if (isNull(schema)) {\n return { type: \"null\" };\n }\n\n if (isArray(schema)) {\n const result: Record<string, unknown> = { type: \"array\" };\n const itemSchema = (schema as { items?: TSchema }).items;\n if (itemSchema) {\n result.items = typeboxToJsonSchema(itemSchema);\n }\n if (schema.minItems !== undefined) result.minItems = schema.minItems;\n if (schema.maxItems !== undefined) result.maxItems = schema.maxItems;\n if (schema.description !== undefined) result.description = schema.description;\n return result;\n }\n\n if (isObject(schema)) {\n const properties = schema.properties as Record<string, TSchema>;\n const required: string[] = schema.required as string[] ?? [];\n const convertedProperties: Record<string, unknown> = {};\n\n for (const [propName, propSchema] of Object.entries(properties)) {\n convertedProperties[propName] = typeboxToJsonSchema(propSchema);\n }\n\n const result: Record<string, unknown> = {\n type: \"object\",\n properties: convertedProperties,\n };\n\n if (required.length > 0) {\n result.required = required;\n }\n\n if (schema.description !== undefined) result.description = schema.description;\n\n return result;\n }\n\n if (isUnion(schema)) {\n return {\n anyOf: schema.anyOf.map((member: TSchema) => typeboxToJsonSchema(member)),\n };\n }\n\n if (isLiteral(schema)) {\n const value = schema.const;\n let type: string;\n if (typeof value === \"string\") {\n type = \"string\";\n } else if (typeof value === \"number\") {\n type = \"number\";\n } else if (typeof value === \"boolean\") {\n type = \"boolean\";\n } else {\n // Fallback for unexpected literal types\n return {};\n }\n return { type, const: value };\n }\n\n // Unknown / unsupported TypeBox type: emit empty schema (accepts anything)\n // This is a safe fallback that allows the MCP tool to still receive input.\n console.warn(\n `[mcp-adapter] Unsupported TypeBox kind: ${(schema as Record<string, unknown>)[\"[Kind]\"] ?? \"(unknown)\"}. Emitting empty schema.`,\n );\n return {};\n}\n\n// ---------------------------------------------------------------------------\n// Input coercion: BigInt string -> BigInt\n// ---------------------------------------------------------------------------\n\n/**\n * Coerce MCP JSON input values to the types expected by a TypeBox schema.\n *\n * MCP transmits all values as JSON, which has no BigInt type. When the schema\n * expects a BigInt, the value arrives as a numeric string (e.g. \"12345678\").\n * This function recursively walks the schema and input, converting BigInt\n * string values to actual BigInt where needed.\n *\n * For all other types the value is passed through unchanged.\n */\nexport function coerceMcpInput(input: unknown, schema: TSchema): unknown {\n if (input === null || input === undefined) return input;\n\n if (isBigInt(schema)) {\n if (typeof input === \"bigint\") return input;\n if (typeof input === \"string\" && /^-?[0-9]+$/.test(input)) {\n try {\n return BigInt(input);\n } catch {\n return input;\n }\n }\n if (typeof input === \"number\") {\n try {\n return BigInt(Math.trunc(input));\n } catch {\n return input;\n }\n }\n return input;\n }\n\n if (isArray(schema)) {\n const itemSchema = (schema as { items?: TSchema }).items;\n if (Array.isArray(input) && itemSchema) {\n return input.map((item) => coerceMcpInput(item, itemSchema));\n }\n return input;\n }\n\n if (isObject(schema)) {\n if (typeof input !== \"object\" || Array.isArray(input)) return input;\n const properties = schema.properties as Record<string, TSchema>;\n const result: Record<string, unknown> = { ...(input as Record<string, unknown>) };\n for (const [propName, propSchema] of Object.entries(properties)) {\n if (propName in result) {\n result[propName] = coerceMcpInput(result[propName], propSchema);\n }\n }\n return result;\n }\n\n if (isUnion(schema)) {\n // For unions, we try each member schema in order and return the first\n // successful coercion. BigInt members take priority over string members\n // since they have a narrower, unambiguous pattern.\n for (const member of schema.anyOf) {\n if (isBigInt(member)) {\n if (typeof input === \"string\" && /^-?[0-9]+$/.test(input)) {\n return coerceMcpInput(input, member);\n }\n }\n }\n // No BigInt match; return as-is for other union members\n return input;\n }\n\n // For all other types (String, Number, Integer, Boolean, Literal, Null):\n // pass through unchanged -- MCP JSON already represents them correctly\n return input;\n}\n\n// ---------------------------------------------------------------------------\n// Lazy MCP SDK import\n// ---------------------------------------------------------------------------\n\n/**\n * MCP SDK module shape (the parts we use from @modelcontextprotocol/sdk).\n * Typed loosely to avoid a hard dependency at compile time.\n */\ninterface IMcpSdkModule {\n // eslint-disable-next-line @typescript-eslint/no-explicit-any\n McpServer: new (opts: { name: string; version: string }) => any;\n}\n\ninterface IStdioTransportModule {\n // eslint-disable-next-line @typescript-eslint/no-explicit-any\n StdioServerTransport: new () => any;\n}\n\n/**\n * Lazily import the MCP SDK server module.\n *\n * Throws a clear, actionable error if the SDK is not installed, rather than\n * a cryptic \"Cannot find module\" Node error.\n */\nexport async function getMcpSdk(): Promise<IMcpSdkModule> {\n try {\n return (await import(\n \"@modelcontextprotocol/sdk/server/mcp.js\"\n )) as IMcpSdkModule;\n } catch {\n throw new Error(\n \"MCP mode requires @modelcontextprotocol/sdk. Install it with: npm install @modelcontextprotocol/sdk\",\n );\n }\n}\n\n/**\n * Lazily import the MCP SDK stdio transport module.\n */\nasync function getMcpStdioTransport(): Promise<IStdioTransportModule> {\n try {\n return (await import(\n \"@modelcontextprotocol/sdk/server/stdio.js\"\n )) as IStdioTransportModule;\n } catch {\n throw new Error(\n \"MCP mode requires @modelcontextprotocol/sdk. Install it with: npm install @modelcontextprotocol/sdk\",\n );\n }\n}\n\n// ---------------------------------------------------------------------------\n// MCP server creation\n// ---------------------------------------------------------------------------\n\n/**\n * Create an MCP server and register all actions from a Sprinkle instance as\n * MCP tools.\n *\n * Each action becomes a tool with:\n * - name: action.name\n * - description: action.description\n * - input schema: typeboxToJsonSchema(action.inputSchema)\n * - handler: coerces input, executes action, returns JSON result\n *\n * The Sprinkle instance must already be initialized with a profile before\n * this function is called.\n *\n * @param sprinkle - Fully-initialized Sprinkle instance\n * @param serverName - Name to use for the MCP server\n * @returns The configured McpServer instance (not yet connected)\n */\nexport async function createMcpServer<S extends TSchema>(\n sprinkle: Sprinkle<S>,\n serverName: string,\n // eslint-disable-next-line @typescript-eslint/no-explicit-any\n): Promise<any> {\n const { McpServer } = await getMcpSdk();\n\n // eslint-disable-next-line @typescript-eslint/no-explicit-any\n const server = new McpServer({ name: serverName, version: PACKAGE_VERSION });\n\n const actions = sprinkle.listActions() as AnyAction<S>[];\n\n for (const action of actions) {\n const inputSchema = typeboxToJsonSchema(action.inputSchema);\n\n // Register the action as an MCP tool.\n // The high-level McpServer.tool() API accepts:\n // tool(name, description, schema, handler)\n server.tool(\n action.name,\n action.description,\n inputSchema,\n // eslint-disable-next-line @typescript-eslint/no-explicit-any\n async (input: unknown): Promise<any> => {\n const coercedInput = coerceMcpInput(input, action.inputSchema);\n\n const context = {\n sprinkle,\n settings: sprinkle.settings,\n };\n\n // eslint-disable-next-line @typescript-eslint/no-explicit-any\n const result = await executeAction(action as any, coercedInput, context as any);\n\n if (result.success) {\n return {\n content: [\n {\n type: \"text\",\n text: JSON.stringify(result.data, bigIntReplacer),\n },\n ],\n };\n } else {\n return {\n content: [\n {\n type: \"text\",\n text: JSON.stringify(\n {\n error: {\n code: result.error.code,\n message: result.error.message,\n details: result.error.details,\n },\n },\n bigIntReplacer,\n ),\n },\n ],\n isError: true,\n };\n }\n },\n );\n }\n\n return server;\n}\n\n// ---------------------------------------------------------------------------\n// MCP orchestrator\n// ---------------------------------------------------------------------------\n\n/**\n * Start an MCP server on stdio transport.\n *\n * This function:\n * 1. Creates the MCP server and registers all actions as tools\n * 2. Creates a StdioServerTransport\n * 3. Connects the server to the transport\n *\n * IMPORTANT: All logging in this function goes to stderr. stdout is reserved\n * for the MCP protocol messages.\n *\n * The Sprinkle instance must already be initialized with a profile. Profile\n * initialization is the responsibility of the caller (Sprinkle.Run()).\n *\n * @param sprinkle - Fully-initialized Sprinkle instance\n * @param serverName - Name to use for the MCP server\n */\nexport async function runMcp<S extends TSchema>(\n sprinkle: Sprinkle<S>,\n serverName: string,\n): Promise<void> {\n const { StdioServerTransport } = await getMcpStdioTransport();\n\n const server = await createMcpServer(sprinkle, serverName);\n const transport = new StdioServerTransport();\n\n try {\n await server.connect(transport);\n } catch (err) {\n // Log errors to stderr only -- stdout is the MCP transport channel\n process.stderr.write(\n `[sprinkle-mcp] Failed to start MCP server: ${err instanceof Error ? err.message : String(err)}\\n`,\n );\n throw err;\n }\n}\n"],"mappings":"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","ignoreList":[]}
@@ -0,0 +1,92 @@
1
+ "use strict";
2
+
3
+ Object.defineProperty(exports, "__esModule", {
4
+ value: true
5
+ });
6
+ exports.ActionRegistry = void 0;
7
+ function _defineProperty(e, r, t) { return (r = _toPropertyKey(r)) in e ? Object.defineProperty(e, r, { value: t, enumerable: !0, configurable: !0, writable: !0 }) : e[r] = t, e; }
8
+ function _toPropertyKey(t) { var i = _toPrimitive(t, "string"); return "symbol" == typeof i ? i : i + ""; }
9
+ function _toPrimitive(t, r) { if ("object" != typeof t || !t) return t; var e = t[Symbol.toPrimitive]; if (void 0 !== e) { var i = e.call(t, r || "default"); if ("object" != typeof i) return i; throw new TypeError("@@toPrimitive must return a primitive value."); } return ("string" === r ? String : Number)(t); }
10
+ /**
11
+ * Action registry for storing and retrieving registered actions.
12
+ */
13
+
14
+ /** Regex for valid kebab-case action names */
15
+ const KEBAB_CASE_REGEX = /^[a-z][a-z0-9]*(-[a-z0-9]+)*$/;
16
+
17
+ /**
18
+ * Registry for managing actions registered on a Sprinkle app.
19
+ * Enforces name uniqueness and schema validation at registration time.
20
+ */
21
+ class ActionRegistry {
22
+ constructor() {
23
+ _defineProperty(this, "actions", new Map());
24
+ }
25
+ /**
26
+ * Register an action with the registry.
27
+ *
28
+ * Validates:
29
+ * - Name is kebab-case (lowercase letters, digits, hyphens)
30
+ * - Name is unique within this registry
31
+ * - inputSchema and outputSchema are present
32
+ *
33
+ * @throws Error if validation fails
34
+ */
35
+ register(action) {
36
+ if (!KEBAB_CASE_REGEX.test(action.name)) {
37
+ throw new Error(`Invalid action name "${action.name}": must be kebab-case (e.g. "my-action", "get-balance")`);
38
+ }
39
+ if (this.actions.has(action.name)) {
40
+ throw new Error(`Action "${action.name}" is already registered. Action names must be unique.`);
41
+ }
42
+ if (!action.inputSchema) {
43
+ throw new Error(`Action "${action.name}" is missing inputSchema. All actions must define an inputSchema.`);
44
+ }
45
+ if (!action.outputSchema) {
46
+ throw new Error(`Action "${action.name}" is missing outputSchema. All actions must define an outputSchema.`);
47
+ }
48
+ this.actions.set(action.name, action);
49
+ }
50
+
51
+ /**
52
+ * Retrieve an action by name.
53
+ * @returns The action, or undefined if not registered
54
+ */
55
+ get(name) {
56
+ return this.actions.get(name);
57
+ }
58
+
59
+ /**
60
+ * Check if an action with the given name is registered.
61
+ */
62
+ has(name) {
63
+ return this.actions.has(name);
64
+ }
65
+
66
+ /**
67
+ * List all registered actions.
68
+ */
69
+ list() {
70
+ return Array.from(this.actions.values());
71
+ }
72
+
73
+ /**
74
+ * Group all registered actions by their category.
75
+ * Actions without a category are placed under "default".
76
+ */
77
+ listByCategory() {
78
+ const result = new Map();
79
+ for (const action of this.actions.values()) {
80
+ const category = action.category ?? "default";
81
+ const bucket = result.get(category);
82
+ if (bucket) {
83
+ bucket.push(action);
84
+ } else {
85
+ result.set(category, [action]);
86
+ }
87
+ }
88
+ return result;
89
+ }
90
+ }
91
+ exports.ActionRegistry = ActionRegistry;
92
+ //# sourceMappingURL=registry.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"registry.js","names":["KEBAB_CASE_REGEX","ActionRegistry","constructor","_defineProperty","Map","register","action","test","name","Error","actions","has","inputSchema","outputSchema","set","get","list","Array","from","values","listByCategory","result","category","bucket","push","exports"],"sources":["../../../../src/Sprinkle/actions/registry.ts"],"sourcesContent":["/**\n * Action registry for storing and retrieving registered actions.\n */\n\nimport type { TSchema } from \"@sinclair/typebox\";\nimport type { AnyAction } from \"./types.js\";\n\n/** Regex for valid kebab-case action names */\nconst KEBAB_CASE_REGEX = /^[a-z][a-z0-9]*(-[a-z0-9]+)*$/;\n\n/**\n * Registry for managing actions registered on a Sprinkle app.\n * Enforces name uniqueness and schema validation at registration time.\n */\nexport class ActionRegistry<S extends TSchema> {\n private actions: Map<string, AnyAction<S>> = new Map();\n\n /**\n * Register an action with the registry.\n *\n * Validates:\n * - Name is kebab-case (lowercase letters, digits, hyphens)\n * - Name is unique within this registry\n * - inputSchema and outputSchema are present\n *\n * @throws Error if validation fails\n */\n register(action: AnyAction<S>): void {\n if (!KEBAB_CASE_REGEX.test(action.name)) {\n throw new Error(\n `Invalid action name \"${action.name}\": must be kebab-case (e.g. \"my-action\", \"get-balance\")`,\n );\n }\n\n if (this.actions.has(action.name)) {\n throw new Error(\n `Action \"${action.name}\" is already registered. Action names must be unique.`,\n );\n }\n\n if (!action.inputSchema) {\n throw new Error(\n `Action \"${action.name}\" is missing inputSchema. All actions must define an inputSchema.`,\n );\n }\n\n if (!action.outputSchema) {\n throw new Error(\n `Action \"${action.name}\" is missing outputSchema. All actions must define an outputSchema.`,\n );\n }\n\n this.actions.set(action.name, action);\n }\n\n /**\n * Retrieve an action by name.\n * @returns The action, or undefined if not registered\n */\n get(name: string): AnyAction<S> | undefined {\n return this.actions.get(name);\n }\n\n /**\n * Check if an action with the given name is registered.\n */\n has(name: string): boolean {\n return this.actions.has(name);\n }\n\n /**\n * List all registered actions.\n */\n list(): AnyAction<S>[] {\n return Array.from(this.actions.values());\n }\n\n /**\n * Group all registered actions by their category.\n * Actions without a category are placed under \"default\".\n */\n listByCategory(): Map<string, AnyAction<S>[]> {\n const result = new Map<string, AnyAction<S>[]>();\n\n for (const action of this.actions.values()) {\n const category = action.category ?? \"default\";\n const bucket = result.get(category);\n if (bucket) {\n bucket.push(action);\n } else {\n result.set(category, [action]);\n }\n }\n\n return result;\n }\n}\n"],"mappings":";;;;;;;;;AAAA;AACA;AACA;;AAKA;AACA,MAAMA,gBAAgB,GAAG,+BAA+B;;AAExD;AACA;AACA;AACA;AACO,MAAMC,cAAc,CAAoB;EAAAC,YAAA;IAAAC,eAAA,kBACA,IAAIC,GAAG,CAAC,CAAC;EAAA;EAEtD;AACF;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;EACEC,QAAQA,CAACC,MAAoB,EAAQ;IACnC,IAAI,CAACN,gBAAgB,CAACO,IAAI,CAACD,MAAM,CAACE,IAAI,CAAC,EAAE;MACvC,MAAM,IAAIC,KAAK,CACb,wBAAwBH,MAAM,CAACE,IAAI,yDACrC,CAAC;IACH;IAEA,IAAI,IAAI,CAACE,OAAO,CAACC,GAAG,CAACL,MAAM,CAACE,IAAI,CAAC,EAAE;MACjC,MAAM,IAAIC,KAAK,CACb,WAAWH,MAAM,CAACE,IAAI,uDACxB,CAAC;IACH;IAEA,IAAI,CAACF,MAAM,CAACM,WAAW,EAAE;MACvB,MAAM,IAAIH,KAAK,CACb,WAAWH,MAAM,CAACE,IAAI,mEACxB,CAAC;IACH;IAEA,IAAI,CAACF,MAAM,CAACO,YAAY,EAAE;MACxB,MAAM,IAAIJ,KAAK,CACb,WAAWH,MAAM,CAACE,IAAI,qEACxB,CAAC;IACH;IAEA,IAAI,CAACE,OAAO,CAACI,GAAG,CAACR,MAAM,CAACE,IAAI,EAAEF,MAAM,CAAC;EACvC;;EAEA;AACF;AACA;AACA;EACES,GAAGA,CAACP,IAAY,EAA4B;IAC1C,OAAO,IAAI,CAACE,OAAO,CAACK,GAAG,CAACP,IAAI,CAAC;EAC/B;;EAEA;AACF;AACA;EACEG,GAAGA,CAACH,IAAY,EAAW;IACzB,OAAO,IAAI,CAACE,OAAO,CAACC,GAAG,CAACH,IAAI,CAAC;EAC/B;;EAEA;AACF;AACA;EACEQ,IAAIA,CAAA,EAAmB;IACrB,OAAOC,KAAK,CAACC,IAAI,CAAC,IAAI,CAACR,OAAO,CAACS,MAAM,CAAC,CAAC,CAAC;EAC1C;;EAEA;AACF;AACA;AACA;EACEC,cAAcA,CAAA,EAAgC;IAC5C,MAAMC,MAAM,GAAG,IAAIjB,GAAG,CAAyB,CAAC;IAEhD,KAAK,MAAME,MAAM,IAAI,IAAI,CAACI,OAAO,CAACS,MAAM,CAAC,CAAC,EAAE;MAC1C,MAAMG,QAAQ,GAAGhB,MAAM,CAACgB,QAAQ,IAAI,SAAS;MAC7C,MAAMC,MAAM,GAAGF,MAAM,CAACN,GAAG,CAACO,QAAQ,CAAC;MACnC,IAAIC,MAAM,EAAE;QACVA,MAAM,CAACC,IAAI,CAAClB,MAAM,CAAC;MACrB,CAAC,MAAM;QACLe,MAAM,CAACP,GAAG,CAACQ,QAAQ,EAAE,CAAChB,MAAM,CAAC,CAAC;MAChC;IACF;IAEA,OAAOe,MAAM;EACf;AACF;AAACI,OAAA,CAAAxB,cAAA,GAAAA,cAAA","ignoreList":[]}