@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,590 @@
1
+ "use strict";
2
+
3
+ var _bunTest = require("bun:test");
4
+ var fs = _interopRequireWildcard(require("fs"));
5
+ var path = _interopRequireWildcard(require("path"));
6
+ var os = _interopRequireWildcard(require("os"));
7
+ var _typebox = require("@sinclair/typebox");
8
+ var _index = require("../index.js");
9
+ var _testHelpers = require("./test-helpers.js");
10
+ 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); }
11
+ // Helper: write a minimal profile file into a tmp storage directory
12
+ function writeTestProfile(storagePath, id, name, settings) {
13
+ const dir = path.join(storagePath, "profiles");
14
+ fs.mkdirSync(dir, {
15
+ recursive: true
16
+ });
17
+ const meta = {
18
+ name,
19
+ createdAt: new Date().toISOString(),
20
+ updatedAt: new Date().toISOString()
21
+ };
22
+ fs.writeFileSync(path.join(dir, `${id}.json`), JSON.stringify({
23
+ meta,
24
+ settings,
25
+ defaults: {}
26
+ }, null, 2), "utf-8");
27
+ }
28
+
29
+ // Simple settings schema used for integration tests
30
+ const TestSchema = _typebox.Type.Object({
31
+ name: _typebox.Type.String()
32
+ });
33
+
34
+ // A reusable valid action
35
+ const greetAction = {
36
+ name: "greet",
37
+ description: "Greets someone",
38
+ inputSchema: _typebox.Type.Object({
39
+ who: _typebox.Type.String()
40
+ }),
41
+ outputSchema: _typebox.Type.Object({
42
+ greeting: _typebox.Type.String()
43
+ }),
44
+ execute: async input => ({
45
+ greeting: `Hello, ${input.who}!`
46
+ })
47
+ };
48
+ (0, _bunTest.describe)("Sprinkle action integration", () => {
49
+ let tmpDir;
50
+ (0, _bunTest.beforeEach)(() => {
51
+ tmpDir = fs.mkdtempSync(path.join(os.tmpdir(), "sprinkles-action-test-"));
52
+ });
53
+ (0, _bunTest.afterEach)(() => {
54
+ fs.rmSync(tmpDir, {
55
+ recursive: true,
56
+ force: true
57
+ });
58
+ });
59
+
60
+ // -------------------------------------------------------------------------
61
+ // actionRegistry field
62
+ // -------------------------------------------------------------------------
63
+
64
+ (0, _bunTest.test)("Sprinkle constructor initialises actionRegistry", () => {
65
+ const sprinkle = new _index.Sprinkle(TestSchema, tmpDir);
66
+ (0, _bunTest.expect)(sprinkle.actionRegistry).toBeInstanceOf(_index.ActionRegistry);
67
+ });
68
+
69
+ // -------------------------------------------------------------------------
70
+ // registerAction / getAction / listActions
71
+ // -------------------------------------------------------------------------
72
+
73
+ (0, _bunTest.test)("registerAction stores an action retrievable via getAction", () => {
74
+ const sprinkle = new _index.Sprinkle(TestSchema, tmpDir);
75
+ sprinkle.registerAction(greetAction);
76
+ (0, _bunTest.expect)(sprinkle.getAction("greet")).toBe(greetAction);
77
+ });
78
+ (0, _bunTest.test)("listActions returns all registered actions", () => {
79
+ const sprinkle = new _index.Sprinkle(TestSchema, tmpDir);
80
+ const actionB = {
81
+ ...greetAction,
82
+ name: "farewell"
83
+ };
84
+ sprinkle.registerAction(greetAction);
85
+ sprinkle.registerAction(actionB);
86
+ (0, _bunTest.expect)(sprinkle.listActions()).toHaveLength(2);
87
+ });
88
+ (0, _bunTest.test)("listActions returns empty array when no actions registered", () => {
89
+ const sprinkle = new _index.Sprinkle(TestSchema, tmpDir);
90
+ (0, _bunTest.expect)(sprinkle.listActions()).toEqual([]);
91
+ });
92
+ (0, _bunTest.test)("getAction returns undefined for unknown action", () => {
93
+ const sprinkle = new _index.Sprinkle(TestSchema, tmpDir);
94
+ (0, _bunTest.expect)(sprinkle.getAction("does-not-exist")).toBeUndefined();
95
+ });
96
+ (0, _bunTest.test)("registerAction throws for duplicate name", () => {
97
+ const sprinkle = new _index.Sprinkle(TestSchema, tmpDir);
98
+ sprinkle.registerAction(greetAction);
99
+ (0, _bunTest.expect)(() => sprinkle.registerAction(greetAction)).toThrow(/already registered/);
100
+ });
101
+ (0, _bunTest.test)("registerAction throws for non-kebab-case name", () => {
102
+ const sprinkle = new _index.Sprinkle(TestSchema, tmpDir);
103
+ (0, _bunTest.expect)(() => sprinkle.registerAction({
104
+ ...greetAction,
105
+ name: "BadName"
106
+ })).toThrow(/Invalid action name/);
107
+ });
108
+
109
+ // -------------------------------------------------------------------------
110
+ // runAction
111
+ // -------------------------------------------------------------------------
112
+
113
+ (0, _bunTest.test)("runAction executes action and returns success result", async () => {
114
+ const sprinkle = (0, _testHelpers.withProfile)(new _index.Sprinkle(TestSchema, tmpDir));
115
+ sprinkle.settings = {
116
+ name: "tester"
117
+ };
118
+ sprinkle.registerAction(greetAction);
119
+ const result = await sprinkle.runAction("greet", {
120
+ who: "World"
121
+ });
122
+ (0, _bunTest.expect)(result.success).toBe(true);
123
+ if (result.success) {
124
+ (0, _bunTest.expect)(result.data).toEqual({
125
+ greeting: "Hello, World!"
126
+ });
127
+ }
128
+ });
129
+ (0, _bunTest.test)("runAction returns failure result on invalid input", async () => {
130
+ const sprinkle = (0, _testHelpers.withProfile)(new _index.Sprinkle(TestSchema, tmpDir));
131
+ sprinkle.settings = {
132
+ name: "tester"
133
+ };
134
+ sprinkle.registerAction(greetAction);
135
+
136
+ // 'who' field is missing
137
+ const result = await sprinkle.runAction("greet", {
138
+ wrongField: "oops"
139
+ });
140
+ (0, _bunTest.expect)(result.success).toBe(false);
141
+ if (!result.success) {
142
+ (0, _bunTest.expect)(result.error.code).toBe("VALIDATION_ERROR");
143
+ }
144
+ });
145
+ (0, _bunTest.test)("runAction throws when action name is not registered", async () => {
146
+ const sprinkle = new _index.Sprinkle(TestSchema, tmpDir);
147
+ await (0, _bunTest.expect)(sprinkle.runAction("not-registered", {})).rejects.toThrow(/not registered/);
148
+ });
149
+ (0, _bunTest.test)("runAction error message lists available actions when none registered", async () => {
150
+ const sprinkle = new _index.Sprinkle(TestSchema, tmpDir);
151
+ await (0, _bunTest.expect)(sprinkle.runAction("nope", {})).rejects.toThrow(/\(none\)/);
152
+ });
153
+ (0, _bunTest.test)("runAction error message lists registered action names", async () => {
154
+ const sprinkle = new _index.Sprinkle(TestSchema, tmpDir);
155
+ sprinkle.registerAction(greetAction);
156
+ await (0, _bunTest.expect)(sprinkle.runAction("nope", {})).rejects.toThrow(/greet/);
157
+ });
158
+ (0, _bunTest.test)("runAction provides sprinkle and settings via context", async () => {
159
+ let capturedContext;
160
+ const ctxAction = {
161
+ name: "ctx-test",
162
+ description: "Captures context",
163
+ inputSchema: _typebox.Type.Object({}),
164
+ outputSchema: _typebox.Type.Object({}),
165
+ execute: async (_input, ctx) => {
166
+ capturedContext = ctx;
167
+ return {};
168
+ }
169
+ };
170
+ const sprinkle = (0, _testHelpers.withProfile)(new _index.Sprinkle(TestSchema, tmpDir));
171
+ sprinkle.settings = {
172
+ name: "ctx-user"
173
+ };
174
+ sprinkle.registerAction(ctxAction);
175
+ await sprinkle.runAction("ctx-test", {});
176
+ (0, _bunTest.expect)(capturedContext.sprinkle).toBe(sprinkle);
177
+ (0, _bunTest.expect)(capturedContext.settings).toEqual({
178
+ name: "ctx-user"
179
+ });
180
+ });
181
+ (0, _bunTest.test)("runAction propagates ActionError from execute without re-wrapping", async () => {
182
+ const myError = new _index.ActionError("deliberate failure", "DELIBERATE", {
183
+ detail: 42
184
+ });
185
+ const failAction = {
186
+ name: "fail-action",
187
+ description: "Always fails",
188
+ inputSchema: _typebox.Type.Object({}),
189
+ outputSchema: _typebox.Type.Object({}),
190
+ execute: async () => {
191
+ throw myError;
192
+ }
193
+ };
194
+ const sprinkle = (0, _testHelpers.withProfile)(new _index.Sprinkle(TestSchema, tmpDir));
195
+ sprinkle.settings = {
196
+ name: "x"
197
+ };
198
+ sprinkle.registerAction(failAction);
199
+ const result = await sprinkle.runAction("fail-action", {});
200
+ (0, _bunTest.expect)(result.success).toBe(false);
201
+ if (!result.success) {
202
+ (0, _bunTest.expect)(result.error).toBe(myError);
203
+ }
204
+ });
205
+
206
+ // -------------------------------------------------------------------------
207
+ // Re-exports from index
208
+ // -------------------------------------------------------------------------
209
+
210
+ (0, _bunTest.test)("ActionRegistry is re-exported from Sprinkle index", () => {
211
+ (0, _bunTest.expect)(_index.ActionRegistry).toBeDefined();
212
+ });
213
+ (0, _bunTest.test)("ActionError is re-exported from Sprinkle index", () => {
214
+ (0, _bunTest.expect)(_index.ActionError).toBeDefined();
215
+ });
216
+
217
+ // -------------------------------------------------------------------------
218
+ // listActionsByCategory
219
+ // -------------------------------------------------------------------------
220
+
221
+ (0, _bunTest.test)("listActionsByCategory returns empty map when no actions registered", () => {
222
+ const sprinkle = new _index.Sprinkle(TestSchema, tmpDir);
223
+ const map = sprinkle.listActionsByCategory();
224
+ (0, _bunTest.expect)(map.size).toBe(0);
225
+ });
226
+ (0, _bunTest.test)("listActionsByCategory places uncategorised actions under 'default'", () => {
227
+ const sprinkle = new _index.Sprinkle(TestSchema, tmpDir);
228
+ sprinkle.registerAction(greetAction); // no category field
229
+ const map = sprinkle.listActionsByCategory();
230
+ (0, _bunTest.expect)(map.has("default")).toBe(true);
231
+ (0, _bunTest.expect)(map.get("default")).toHaveLength(1);
232
+ (0, _bunTest.expect)(map.get("default")[0].name).toBe("greet");
233
+ });
234
+ (0, _bunTest.test)("listActionsByCategory groups categorised actions correctly", () => {
235
+ const sprinkle = new _index.Sprinkle(TestSchema, tmpDir);
236
+ const alpha1 = {
237
+ ...greetAction,
238
+ name: "alpha-one",
239
+ category: "alpha"
240
+ };
241
+ const alpha2 = {
242
+ ...greetAction,
243
+ name: "alpha-two",
244
+ category: "alpha"
245
+ };
246
+ const beta1 = {
247
+ ...greetAction,
248
+ name: "beta-one",
249
+ category: "beta"
250
+ };
251
+ sprinkle.registerAction(alpha1);
252
+ sprinkle.registerAction(alpha2);
253
+ sprinkle.registerAction(beta1);
254
+ const map = sprinkle.listActionsByCategory();
255
+ (0, _bunTest.expect)(map.get("alpha")).toHaveLength(2);
256
+ (0, _bunTest.expect)(map.get("beta")).toHaveLength(1);
257
+ (0, _bunTest.expect)(map.has("default")).toBe(false);
258
+ });
259
+ (0, _bunTest.test)("listActionsByCategory mixes categorised and uncategorised actions", () => {
260
+ const sprinkle = new _index.Sprinkle(TestSchema, tmpDir);
261
+ const categorised = {
262
+ ...greetAction,
263
+ name: "cat-action",
264
+ category: "tools"
265
+ };
266
+ sprinkle.registerAction(greetAction); // uncategorised
267
+ sprinkle.registerAction(categorised);
268
+ const map = sprinkle.listActionsByCategory();
269
+ (0, _bunTest.expect)(map.get("default")).toHaveLength(1);
270
+ (0, _bunTest.expect)(map.get("tools")).toHaveLength(1);
271
+ });
272
+ });
273
+
274
+ // ---------------------------------------------------------------------------
275
+ // Sprinkle.run() static entry point
276
+ // ---------------------------------------------------------------------------
277
+
278
+ (0, _bunTest.describe)("Sprinkle.run() static entry point", () => {
279
+ let tmpDir;
280
+ let logSpy;
281
+ let errorSpy;
282
+ let exitSpy;
283
+ (0, _bunTest.beforeEach)(() => {
284
+ tmpDir = fs.mkdtempSync(path.join(os.tmpdir(), "sprinkles-run-test-"));
285
+ logSpy = (0, _bunTest.spyOn)(console, "log").mockImplementation(() => {});
286
+ errorSpy = (0, _bunTest.spyOn)(console, "error").mockImplementation(() => {});
287
+ exitSpy = (0, _bunTest.spyOn)(process, "exit").mockImplementation(() => {
288
+ throw new Error("process.exit called");
289
+ });
290
+ });
291
+ (0, _bunTest.afterEach)(() => {
292
+ fs.rmSync(tmpDir, {
293
+ recursive: true,
294
+ force: true
295
+ });
296
+ logSpy.mockRestore();
297
+ errorSpy.mockRestore();
298
+ exitSpy.mockRestore();
299
+ });
300
+
301
+ // -------------------------------------------------------------------------
302
+ // help mode
303
+ // -------------------------------------------------------------------------
304
+
305
+ (0, _bunTest.test)("help mode prints 'No actions registered.' when no actions provided", async () => {
306
+ await _index.Sprinkle.run({
307
+ type: TestSchema,
308
+ storagePath: tmpDir,
309
+ argv: ["--help"]
310
+ });
311
+ const output = logSpy.mock.calls.map(c => String(c[0])).join("\n");
312
+ (0, _bunTest.expect)(output).toContain("No actions registered.");
313
+ });
314
+ (0, _bunTest.test)("help mode prints 'Available actions:' header when actions are registered", async () => {
315
+ await _index.Sprinkle.run({
316
+ type: TestSchema,
317
+ storagePath: tmpDir,
318
+ actions: [greetAction],
319
+ argv: ["--help"]
320
+ });
321
+ const output = logSpy.mock.calls.map(c => String(c[0])).join("\n");
322
+ (0, _bunTest.expect)(output).toContain("Available actions:");
323
+ });
324
+ (0, _bunTest.test)("help mode lists registered action name and description", async () => {
325
+ await _index.Sprinkle.run({
326
+ type: TestSchema,
327
+ storagePath: tmpDir,
328
+ actions: [greetAction],
329
+ argv: ["--help"]
330
+ });
331
+ const output = logSpy.mock.calls.map(c => String(c[0])).join("\n");
332
+ (0, _bunTest.expect)(output).toContain("greet");
333
+ (0, _bunTest.expect)(output).toContain("Greets someone");
334
+ });
335
+ (0, _bunTest.test)("help mode prints category header for categorised actions", async () => {
336
+ const catAction = {
337
+ ...greetAction,
338
+ name: "do-thing",
339
+ category: "tools"
340
+ };
341
+ await _index.Sprinkle.run({
342
+ type: TestSchema,
343
+ storagePath: tmpDir,
344
+ actions: [catAction],
345
+ argv: ["--help"]
346
+ });
347
+ const output = logSpy.mock.calls.map(c => String(c[0])).join("\n");
348
+ (0, _bunTest.expect)(output).toContain("tools:");
349
+ });
350
+ (0, _bunTest.test)("help mode does not print 'default:' header for uncategorised actions", async () => {
351
+ await _index.Sprinkle.run({
352
+ type: TestSchema,
353
+ storagePath: tmpDir,
354
+ actions: [greetAction],
355
+ argv: ["--help"]
356
+ });
357
+ const output = logSpy.mock.calls.map(c => String(c[0])).join("\n");
358
+ (0, _bunTest.expect)(output).not.toContain("default:");
359
+ });
360
+ (0, _bunTest.test)("help mode also triggers with -h flag", async () => {
361
+ await _index.Sprinkle.run({
362
+ type: TestSchema,
363
+ storagePath: tmpDir,
364
+ argv: ["-h"]
365
+ });
366
+ const output = logSpy.mock.calls.map(c => String(c[0])).join("\n");
367
+ (0, _bunTest.expect)(output).toContain("No actions registered.");
368
+ });
369
+
370
+ // -------------------------------------------------------------------------
371
+ // CLI mode
372
+ // -------------------------------------------------------------------------
373
+
374
+ (0, _bunTest.test)("CLI mode executes action and writes JSON result to stdout", async () => {
375
+ writeTestProfile(tmpDir, "default", "Default", {
376
+ name: "tester"
377
+ });
378
+ await _index.Sprinkle.run({
379
+ type: TestSchema,
380
+ storagePath: tmpDir,
381
+ actions: [greetAction],
382
+ argv: ["greet", "--who", "World"]
383
+ });
384
+ const calls = logSpy.mock.calls.map(c => String(c[0]));
385
+ const jsonLine = calls.find(l => {
386
+ try {
387
+ JSON.parse(l);
388
+ return true;
389
+ } catch {
390
+ return false;
391
+ }
392
+ });
393
+ (0, _bunTest.expect)(jsonLine).toBeDefined();
394
+ const parsed = JSON.parse(jsonLine);
395
+ (0, _bunTest.expect)(parsed.success).toBe(true);
396
+ (0, _bunTest.expect)(parsed.data).toEqual({
397
+ greeting: "Hello, World!"
398
+ });
399
+ });
400
+ (0, _bunTest.test)("CLI mode result contains success:false for invalid input", async () => {
401
+ writeTestProfile(tmpDir, "default", "Default", {
402
+ name: "tester"
403
+ });
404
+ await (0, _bunTest.expect)(_index.Sprinkle.run({
405
+ type: TestSchema,
406
+ storagePath: tmpDir,
407
+ actions: [greetAction],
408
+ argv: ["greet"]
409
+ })).rejects.toThrow("process.exit called");
410
+ const calls = errorSpy.mock.calls.map(c => String(c[0]));
411
+ const jsonLine = calls.find(l => {
412
+ try {
413
+ JSON.parse(l);
414
+ return true;
415
+ } catch {
416
+ return false;
417
+ }
418
+ });
419
+ (0, _bunTest.expect)(jsonLine).toBeDefined();
420
+ const parsed = JSON.parse(jsonLine);
421
+ (0, _bunTest.expect)(parsed.success).toBe(false);
422
+ (0, _bunTest.expect)(parsed.error.code).toBe("VALIDATION_ERROR");
423
+ (0, _bunTest.expect)(exitSpy).toHaveBeenCalledWith(1);
424
+ });
425
+ (0, _bunTest.test)("CLI mode --profile flag selects the named profile", async () => {
426
+ writeTestProfile(tmpDir, "alice", "Alice", {
427
+ name: "alice"
428
+ });
429
+ writeTestProfile(tmpDir, "bob", "Bob", {
430
+ name: "bob"
431
+ });
432
+ let capturedSettings;
433
+ const captureAction = {
434
+ name: "capture",
435
+ description: "Captures settings",
436
+ inputSchema: _typebox.Type.Object({}),
437
+ outputSchema: _typebox.Type.Object({
438
+ name: _typebox.Type.String()
439
+ }),
440
+ execute: async (_input, ctx) => {
441
+ capturedSettings = ctx.settings;
442
+ return {
443
+ name: ctx.settings.name
444
+ };
445
+ }
446
+ };
447
+ await _index.Sprinkle.run({
448
+ type: TestSchema,
449
+ storagePath: tmpDir,
450
+ actions: [captureAction],
451
+ argv: ["capture", "--profile", "alice"]
452
+ });
453
+ (0, _bunTest.expect)(capturedSettings).toBeDefined();
454
+ (0, _bunTest.expect)(capturedSettings.name).toBe("alice");
455
+ });
456
+ (0, _bunTest.test)("CLI mode --profile flag selects the correct profile when multiple exist", async () => {
457
+ writeTestProfile(tmpDir, "alice", "Alice", {
458
+ name: "alice"
459
+ });
460
+ writeTestProfile(tmpDir, "bob", "Bob", {
461
+ name: "bob"
462
+ });
463
+ const captureAction = {
464
+ name: "capture-two",
465
+ description: "Captures settings",
466
+ inputSchema: _typebox.Type.Object({}),
467
+ outputSchema: _typebox.Type.Object({
468
+ name: _typebox.Type.String()
469
+ }),
470
+ execute: async (_input, ctx) => ({
471
+ name: ctx.settings.name
472
+ })
473
+ };
474
+ await _index.Sprinkle.run({
475
+ type: TestSchema,
476
+ storagePath: tmpDir,
477
+ actions: [captureAction],
478
+ argv: ["capture-two", "--profile", "bob"]
479
+ });
480
+ const calls = logSpy.mock.calls.map(c => String(c[0]));
481
+ const jsonLine = calls.find(l => {
482
+ try {
483
+ JSON.parse(l);
484
+ return true;
485
+ } catch {
486
+ return false;
487
+ }
488
+ });
489
+ const parsed = JSON.parse(jsonLine);
490
+ (0, _bunTest.expect)(parsed.success).toBe(true);
491
+ (0, _bunTest.expect)(parsed.data.name).toBe("bob");
492
+ });
493
+ (0, _bunTest.test)("CLI mode auto-selects the only profile when no --profile flag given", async () => {
494
+ writeTestProfile(tmpDir, "solo", "Solo", {
495
+ name: "solo-user"
496
+ });
497
+ const captureAction = {
498
+ name: "capture-auto",
499
+ description: "Captures settings",
500
+ inputSchema: _typebox.Type.Object({}),
501
+ outputSchema: _typebox.Type.Object({
502
+ name: _typebox.Type.String()
503
+ }),
504
+ execute: async (_input, ctx) => ({
505
+ name: ctx.settings.name
506
+ })
507
+ };
508
+ await _index.Sprinkle.run({
509
+ type: TestSchema,
510
+ storagePath: tmpDir,
511
+ actions: [captureAction],
512
+ argv: ["capture-auto"]
513
+ });
514
+ const calls = logSpy.mock.calls.map(c => String(c[0]));
515
+ const jsonLine = calls.find(l => {
516
+ try {
517
+ JSON.parse(l);
518
+ return true;
519
+ } catch {
520
+ return false;
521
+ }
522
+ });
523
+ const parsed = JSON.parse(jsonLine);
524
+ (0, _bunTest.expect)(parsed.success).toBe(true);
525
+ (0, _bunTest.expect)(parsed.data.name).toBe("solo-user");
526
+ });
527
+ (0, _bunTest.test)("CLI mode throws when multiple profiles exist and no --profile flag given", async () => {
528
+ writeTestProfile(tmpDir, "alice", "Alice", {
529
+ name: "alice"
530
+ });
531
+ writeTestProfile(tmpDir, "bob", "Bob", {
532
+ name: "bob"
533
+ });
534
+ await (0, _bunTest.expect)(_index.Sprinkle.run({
535
+ type: TestSchema,
536
+ storagePath: tmpDir,
537
+ actions: [greetAction],
538
+ argv: ["greet", "--who", "World"]
539
+ })).rejects.toThrow(/--profile/);
540
+ });
541
+ (0, _bunTest.test)("CLI mode throws when no profiles exist", async () => {
542
+ await (0, _bunTest.expect)(_index.Sprinkle.run({
543
+ type: TestSchema,
544
+ storagePath: tmpDir,
545
+ actions: [greetAction],
546
+ argv: ["greet", "--who", "World"]
547
+ })).rejects.toThrow(/No profiles found/);
548
+ });
549
+
550
+ // -------------------------------------------------------------------------
551
+ // TUI mode
552
+ // -------------------------------------------------------------------------
553
+
554
+ (0, _bunTest.test)("TUI mode throws when no menu option is provided", async () => {
555
+ await (0, _bunTest.expect)(_index.Sprinkle.run({
556
+ type: TestSchema,
557
+ storagePath: tmpDir,
558
+ argv: []
559
+ })).rejects.toThrow(/TUI mode requires a menu/);
560
+ });
561
+ (0, _bunTest.test)("TUI mode throws when --interactive flag is passed without a menu", async () => {
562
+ await (0, _bunTest.expect)(_index.Sprinkle.run({
563
+ type: TestSchema,
564
+ storagePath: tmpDir,
565
+ argv: ["--interactive"]
566
+ })).rejects.toThrow(/TUI mode requires a menu/);
567
+ });
568
+
569
+ // -------------------------------------------------------------------------
570
+ // MCP mode
571
+ // -------------------------------------------------------------------------
572
+
573
+ (0, _bunTest.test)("MCP mode throws when SDK is not installed", async () => {
574
+ // MCP mode is implemented but requires the optional @modelcontextprotocol/sdk
575
+ // peer dependency. When the SDK is available (as in this dev environment),
576
+ // MCP mode will attempt to start a server. When the SDK is not installed,
577
+ // it should throw a clear error message with install instructions.
578
+ //
579
+ // In CI/dev with the SDK installed, MCP mode will attempt to connect to
580
+ // stdio transport. We test the error path by verifying the mode no longer
581
+ // throws "not yet implemented" -- specific MCP behavior is tested in
582
+ // mcp-adapter.test.ts.
583
+ await (0, _bunTest.expect)(_index.Sprinkle.run({
584
+ type: TestSchema,
585
+ storagePath: tmpDir,
586
+ argv: ["--mcp"]
587
+ })).rejects.not.toThrow(/not yet implemented/i);
588
+ });
589
+ });
590
+ //# sourceMappingURL=action-integration.test.js.map