@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,1110 @@
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
+ 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); }
10
+ // Helper: write a minimal profile file into a tmp storage directory
11
+ function writeTestProfile(storagePath, id, name, settings, description) {
12
+ const dir = path.join(storagePath, "profiles");
13
+ fs.mkdirSync(dir, {
14
+ recursive: true
15
+ });
16
+ const meta = {
17
+ name,
18
+ description,
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
+ // Settings schema with a sensitive field for masking tests
30
+ const TestSchema = _typebox.Type.Object({
31
+ name: _typebox.Type.String(),
32
+ token: _typebox.Type.Optional(_typebox.Type.String({
33
+ sensitive: true
34
+ }))
35
+ });
36
+
37
+ // Simple schema without sensitive fields
38
+ const SimpleSchema = _typebox.Type.Object({
39
+ name: _typebox.Type.String()
40
+ });
41
+
42
+ // Helper: create a Sprinkle with a loaded profile ready for action execution
43
+ async function makeSprinkle(storagePath, profileId = "default", settings = {
44
+ name: "tester"
45
+ }) {
46
+ const sprinkle = new _index.Sprinkle(SimpleSchema, storagePath);
47
+ writeTestProfile(storagePath, profileId, "Default", settings);
48
+ await sprinkle.loadProfile(profileId);
49
+ return sprinkle;
50
+ }
51
+ (0, _bunTest.describe)("getBuiltinActions", () => {
52
+ (0, _bunTest.test)("returns an array of 14 actions", () => {
53
+ const actions = (0, _index.getBuiltinActions)();
54
+ (0, _bunTest.expect)(actions).toHaveLength(14);
55
+ });
56
+ (0, _bunTest.test)("all actions have a category", () => {
57
+ const actions = (0, _index.getBuiltinActions)();
58
+ const validCategories = ["sprinkles", "wallet", "transaction"];
59
+ for (const action of actions) {
60
+ (0, _bunTest.expect)(validCategories).toContain(action.category);
61
+ }
62
+ });
63
+ (0, _bunTest.test)("returns actions with expected names", () => {
64
+ const names = (0, _index.getBuiltinActions)().map(a => a.name);
65
+ (0, _bunTest.expect)(names).toContain("list-profiles");
66
+ (0, _bunTest.expect)(names).toContain("get-profile");
67
+ (0, _bunTest.expect)(names).toContain("set-profile");
68
+ (0, _bunTest.expect)(names).toContain("create-profile");
69
+ (0, _bunTest.expect)(names).toContain("delete-profile");
70
+ (0, _bunTest.expect)(names).toContain("get-settings");
71
+ (0, _bunTest.expect)(names).toContain("update-settings");
72
+ });
73
+ (0, _bunTest.test)("all actions have inputSchema and outputSchema", () => {
74
+ const actions = (0, _index.getBuiltinActions)();
75
+ for (const action of actions) {
76
+ (0, _bunTest.expect)(action.inputSchema).toBeDefined();
77
+ (0, _bunTest.expect)(action.outputSchema).toBeDefined();
78
+ }
79
+ });
80
+ (0, _bunTest.test)("built-in actions can be registered on a Sprinkle instance", () => {
81
+ const sprinkle = new _index.Sprinkle(SimpleSchema, os.tmpdir());
82
+ const actions = (0, _index.getBuiltinActions)();
83
+ for (const action of actions) {
84
+ sprinkle.registerAction(action);
85
+ }
86
+ (0, _bunTest.expect)(sprinkle.listActions()).toHaveLength(14);
87
+ });
88
+ });
89
+
90
+ // ---------------------------------------------------------------------------
91
+ // list-profiles
92
+ // ---------------------------------------------------------------------------
93
+
94
+ (0, _bunTest.describe)("list-profiles action", () => {
95
+ let tmpDir;
96
+ (0, _bunTest.beforeEach)(() => {
97
+ tmpDir = fs.mkdtempSync(path.join(os.tmpdir(), "sprinkles-builtin-test-"));
98
+ });
99
+ (0, _bunTest.afterEach)(() => {
100
+ fs.rmSync(tmpDir, {
101
+ recursive: true,
102
+ force: true
103
+ });
104
+ });
105
+ (0, _bunTest.test)("returns empty profiles array when no profiles exist", async () => {
106
+ const sprinkle = new _index.Sprinkle(SimpleSchema, tmpDir);
107
+ for (const action of (0, _index.getBuiltinActions)()) {
108
+ sprinkle.registerAction(action);
109
+ }
110
+ const result = await sprinkle.runAction("list-profiles", {});
111
+ (0, _bunTest.expect)(result.success).toBe(true);
112
+ if (result.success) {
113
+ (0, _bunTest.expect)(result.data.profiles).toEqual([]);
114
+ }
115
+ });
116
+ (0, _bunTest.test)("returns all profiles with expected fields", async () => {
117
+ writeTestProfile(tmpDir, "alice", "Alice", {
118
+ name: "alice"
119
+ });
120
+ writeTestProfile(tmpDir, "bob", "Bob", {
121
+ name: "bob"
122
+ });
123
+ const sprinkle = new _index.Sprinkle(SimpleSchema, tmpDir);
124
+ await sprinkle.loadProfile("alice");
125
+ for (const action of (0, _index.getBuiltinActions)()) {
126
+ sprinkle.registerAction(action);
127
+ }
128
+ const result = await sprinkle.runAction("list-profiles", {});
129
+ (0, _bunTest.expect)(result.success).toBe(true);
130
+ if (result.success) {
131
+ (0, _bunTest.expect)(result.data.profiles).toHaveLength(2);
132
+ const names = result.data.profiles.map(p => p.name);
133
+ (0, _bunTest.expect)(names).toContain("Alice");
134
+ (0, _bunTest.expect)(names).toContain("Bob");
135
+ }
136
+ });
137
+ (0, _bunTest.test)("includes activeProfileId when a profile is loaded", async () => {
138
+ writeTestProfile(tmpDir, "default", "Default", {
139
+ name: "tester"
140
+ });
141
+ const sprinkle = new _index.Sprinkle(SimpleSchema, tmpDir);
142
+ await sprinkle.loadProfile("default");
143
+ for (const action of (0, _index.getBuiltinActions)()) {
144
+ sprinkle.registerAction(action);
145
+ }
146
+ const result = await sprinkle.runAction("list-profiles", {});
147
+ (0, _bunTest.expect)(result.success).toBe(true);
148
+ if (result.success) {
149
+ (0, _bunTest.expect)(result.data.activeProfileId).toBe("default");
150
+ }
151
+ });
152
+ (0, _bunTest.test)("activeProfileId is undefined when no profile is loaded", async () => {
153
+ const sprinkle = new _index.Sprinkle(SimpleSchema, tmpDir);
154
+ for (const action of (0, _index.getBuiltinActions)()) {
155
+ sprinkle.registerAction(action);
156
+ }
157
+ const result = await sprinkle.runAction("list-profiles", {});
158
+ (0, _bunTest.expect)(result.success).toBe(true);
159
+ if (result.success) {
160
+ (0, _bunTest.expect)(result.data.activeProfileId).toBeUndefined();
161
+ }
162
+ });
163
+ (0, _bunTest.test)("each profile entry contains id, name, createdAt, updatedAt", async () => {
164
+ writeTestProfile(tmpDir, "alpha", "Alpha Profile", {
165
+ name: "alpha"
166
+ }, "A profile");
167
+ const sprinkle = new _index.Sprinkle(SimpleSchema, tmpDir);
168
+ await sprinkle.loadProfile("alpha");
169
+ for (const action of (0, _index.getBuiltinActions)()) {
170
+ sprinkle.registerAction(action);
171
+ }
172
+ const result = await sprinkle.runAction("list-profiles", {});
173
+ (0, _bunTest.expect)(result.success).toBe(true);
174
+ if (result.success) {
175
+ const profile = result.data.profiles[0];
176
+ (0, _bunTest.expect)(profile.id).toBe("alpha");
177
+ (0, _bunTest.expect)(profile.name).toBe("Alpha Profile");
178
+ (0, _bunTest.expect)(profile.description).toBe("A profile");
179
+ (0, _bunTest.expect)(profile.createdAt).toBeDefined();
180
+ (0, _bunTest.expect)(profile.updatedAt).toBeDefined();
181
+ }
182
+ });
183
+ });
184
+
185
+ // ---------------------------------------------------------------------------
186
+ // get-profile
187
+ // ---------------------------------------------------------------------------
188
+
189
+ (0, _bunTest.describe)("get-profile action", () => {
190
+ let tmpDir;
191
+ (0, _bunTest.beforeEach)(() => {
192
+ tmpDir = fs.mkdtempSync(path.join(os.tmpdir(), "sprinkles-builtin-test-"));
193
+ });
194
+ (0, _bunTest.afterEach)(() => {
195
+ fs.rmSync(tmpDir, {
196
+ recursive: true,
197
+ force: true
198
+ });
199
+ });
200
+ (0, _bunTest.test)("returns profile metadata and settings for a valid id", async () => {
201
+ writeTestProfile(tmpDir, "myprofile", "My Profile", {
202
+ name: "hello"
203
+ });
204
+ const sprinkle = new _index.Sprinkle(SimpleSchema, tmpDir);
205
+ await sprinkle.loadProfile("myprofile");
206
+ for (const action of (0, _index.getBuiltinActions)()) {
207
+ sprinkle.registerAction(action);
208
+ }
209
+ const result = await sprinkle.runAction("get-profile", {
210
+ id: "myprofile"
211
+ });
212
+ (0, _bunTest.expect)(result.success).toBe(true);
213
+ if (result.success) {
214
+ (0, _bunTest.expect)(result.data.id).toBe("myprofile");
215
+ (0, _bunTest.expect)(result.data.name).toBe("My Profile");
216
+ (0, _bunTest.expect)(result.data.settings).toBeDefined();
217
+ }
218
+ });
219
+ (0, _bunTest.test)("returns PROFILE_NOT_FOUND for unknown profile id", async () => {
220
+ writeTestProfile(tmpDir, "existing", "Existing", {
221
+ name: "x"
222
+ });
223
+ const sprinkle = new _index.Sprinkle(SimpleSchema, tmpDir);
224
+ await sprinkle.loadProfile("existing");
225
+ for (const action of (0, _index.getBuiltinActions)()) {
226
+ sprinkle.registerAction(action);
227
+ }
228
+ const result = await sprinkle.runAction("get-profile", {
229
+ id: "no-such-profile"
230
+ });
231
+ (0, _bunTest.expect)(result.success).toBe(false);
232
+ if (!result.success) {
233
+ (0, _bunTest.expect)(result.error.code).toBe("PROFILE_NOT_FOUND");
234
+ }
235
+ });
236
+ (0, _bunTest.test)("settings are returned when includeSensitive is not specified (defaults to masked)", async () => {
237
+ writeTestProfile(tmpDir, "prof1", "Prof1", {
238
+ name: "value"
239
+ });
240
+ const sprinkle = new _index.Sprinkle(SimpleSchema, tmpDir);
241
+ await sprinkle.loadProfile("prof1");
242
+ for (const action of (0, _index.getBuiltinActions)()) {
243
+ sprinkle.registerAction(action);
244
+ }
245
+ const result = await sprinkle.runAction("get-profile", {
246
+ id: "prof1"
247
+ });
248
+ (0, _bunTest.expect)(result.success).toBe(true);
249
+ if (result.success) {
250
+ (0, _bunTest.expect)(result.data.settings).toBeDefined();
251
+ }
252
+ });
253
+ (0, _bunTest.test)("returns raw settings when includeSensitive is true", async () => {
254
+ writeTestProfile(tmpDir, "prof2", "Prof2", {
255
+ name: "raw-value"
256
+ });
257
+ const sprinkle = new _index.Sprinkle(SimpleSchema, tmpDir);
258
+ await sprinkle.loadProfile("prof2");
259
+ for (const action of (0, _index.getBuiltinActions)()) {
260
+ sprinkle.registerAction(action);
261
+ }
262
+ const result = await sprinkle.runAction("get-profile", {
263
+ id: "prof2",
264
+ includeSensitive: true
265
+ });
266
+ (0, _bunTest.expect)(result.success).toBe(true);
267
+ if (result.success) {
268
+ (0, _bunTest.expect)(result.data.settings.name).toBe("raw-value");
269
+ }
270
+ });
271
+ (0, _bunTest.test)("error details include the requested id", async () => {
272
+ writeTestProfile(tmpDir, "existing", "Existing", {
273
+ name: "x"
274
+ });
275
+ const sprinkle = new _index.Sprinkle(SimpleSchema, tmpDir);
276
+ await sprinkle.loadProfile("existing");
277
+ for (const action of (0, _index.getBuiltinActions)()) {
278
+ sprinkle.registerAction(action);
279
+ }
280
+ const result = await sprinkle.runAction("get-profile", {
281
+ id: "ghost"
282
+ });
283
+ (0, _bunTest.expect)(result.success).toBe(false);
284
+ if (!result.success) {
285
+ (0, _bunTest.expect)(result.error.details).toMatchObject({
286
+ id: "ghost"
287
+ });
288
+ }
289
+ });
290
+ (0, _bunTest.test)("returns INVALID_PROFILE_ID for path traversal attempts", async () => {
291
+ writeTestProfile(tmpDir, "existing", "Existing", {
292
+ name: "x"
293
+ });
294
+ const sprinkle = new _index.Sprinkle(SimpleSchema, tmpDir);
295
+ await sprinkle.loadProfile("existing");
296
+ for (const action of (0, _index.getBuiltinActions)()) {
297
+ sprinkle.registerAction(action);
298
+ }
299
+ const result = await sprinkle.runAction("get-profile", {
300
+ id: "../etc/passwd"
301
+ });
302
+ (0, _bunTest.expect)(result.success).toBe(false);
303
+ if (!result.success) {
304
+ (0, _bunTest.expect)(result.error.code).toBe("INVALID_PROFILE_ID");
305
+ }
306
+ });
307
+ (0, _bunTest.test)("masks sensitive fields by default with TestSchema", async () => {
308
+ // Write profile with a sensitive token field
309
+ writeTestProfile(tmpDir, "sensitive-test", "Sensitive Test", {
310
+ name: "user",
311
+ token: "secret-api-key-12345"
312
+ });
313
+ const sprinkle = new _index.Sprinkle(TestSchema, tmpDir);
314
+ await sprinkle.loadProfile("sensitive-test");
315
+ for (const action of (0, _index.getBuiltinActions)()) {
316
+ sprinkle.registerAction(action);
317
+ }
318
+ const result = await sprinkle.runAction("get-profile", {
319
+ id: "sensitive-test"
320
+ });
321
+ (0, _bunTest.expect)(result.success).toBe(true);
322
+ if (result.success) {
323
+ // Token should be masked
324
+ (0, _bunTest.expect)(result.data.settings.token).toBe("********");
325
+ // Name should not be masked
326
+ (0, _bunTest.expect)(result.data.settings.name).toBe("user");
327
+ }
328
+ });
329
+ (0, _bunTest.test)("returns raw sensitive fields when includeSensitive is true with TestSchema", async () => {
330
+ writeTestProfile(tmpDir, "sensitive-raw", "Sensitive Raw", {
331
+ name: "user",
332
+ token: "my-secret-token"
333
+ });
334
+ const sprinkle = new _index.Sprinkle(TestSchema, tmpDir);
335
+ await sprinkle.loadProfile("sensitive-raw");
336
+ for (const action of (0, _index.getBuiltinActions)()) {
337
+ sprinkle.registerAction(action);
338
+ }
339
+ const result = await sprinkle.runAction("get-profile", {
340
+ id: "sensitive-raw",
341
+ includeSensitive: true
342
+ });
343
+ (0, _bunTest.expect)(result.success).toBe(true);
344
+ if (result.success) {
345
+ // Token should NOT be masked
346
+ (0, _bunTest.expect)(result.data.settings.token).toBe("my-secret-token");
347
+ (0, _bunTest.expect)(result.data.settings.name).toBe("user");
348
+ }
349
+ });
350
+ });
351
+
352
+ // ---------------------------------------------------------------------------
353
+ // set-profile
354
+ // ---------------------------------------------------------------------------
355
+
356
+ (0, _bunTest.describe)("set-profile action", () => {
357
+ let tmpDir;
358
+ (0, _bunTest.beforeEach)(() => {
359
+ tmpDir = fs.mkdtempSync(path.join(os.tmpdir(), "sprinkles-builtin-test-"));
360
+ });
361
+ (0, _bunTest.afterEach)(() => {
362
+ fs.rmSync(tmpDir, {
363
+ recursive: true,
364
+ force: true
365
+ });
366
+ });
367
+ (0, _bunTest.test)("switches active profile and returns id and name", async () => {
368
+ writeTestProfile(tmpDir, "alice", "Alice", {
369
+ name: "alice"
370
+ });
371
+ writeTestProfile(tmpDir, "bob", "Bob", {
372
+ name: "bob"
373
+ });
374
+ const sprinkle = new _index.Sprinkle(SimpleSchema, tmpDir);
375
+ await sprinkle.loadProfile("alice");
376
+ for (const action of (0, _index.getBuiltinActions)()) {
377
+ sprinkle.registerAction(action);
378
+ }
379
+ const result = await sprinkle.runAction("set-profile", {
380
+ id: "bob"
381
+ });
382
+ (0, _bunTest.expect)(result.success).toBe(true);
383
+ if (result.success) {
384
+ (0, _bunTest.expect)(result.data.id).toBe("bob");
385
+ (0, _bunTest.expect)(result.data.name).toBe("Bob");
386
+ }
387
+ });
388
+ (0, _bunTest.test)("active profile is actually changed after set-profile", async () => {
389
+ writeTestProfile(tmpDir, "alice", "Alice", {
390
+ name: "alice"
391
+ });
392
+ writeTestProfile(tmpDir, "bob", "Bob", {
393
+ name: "bob"
394
+ });
395
+ const sprinkle = new _index.Sprinkle(SimpleSchema, tmpDir);
396
+ await sprinkle.loadProfile("alice");
397
+ for (const action of (0, _index.getBuiltinActions)()) {
398
+ sprinkle.registerAction(action);
399
+ }
400
+ await sprinkle.runAction("set-profile", {
401
+ id: "bob"
402
+ });
403
+ (0, _bunTest.expect)(sprinkle.profileId).toBe("bob");
404
+ });
405
+ (0, _bunTest.test)("returns PROFILE_NOT_FOUND when switching to unknown profile", async () => {
406
+ writeTestProfile(tmpDir, "alice", "Alice", {
407
+ name: "alice"
408
+ });
409
+ const sprinkle = new _index.Sprinkle(SimpleSchema, tmpDir);
410
+ await sprinkle.loadProfile("alice");
411
+ for (const action of (0, _index.getBuiltinActions)()) {
412
+ sprinkle.registerAction(action);
413
+ }
414
+ const result = await sprinkle.runAction("set-profile", {
415
+ id: "nobody"
416
+ });
417
+ (0, _bunTest.expect)(result.success).toBe(false);
418
+ if (!result.success) {
419
+ (0, _bunTest.expect)(result.error.code).toBe("PROFILE_NOT_FOUND");
420
+ }
421
+ });
422
+ });
423
+
424
+ // ---------------------------------------------------------------------------
425
+ // create-profile
426
+ // ---------------------------------------------------------------------------
427
+
428
+ (0, _bunTest.describe)("create-profile action", () => {
429
+ let tmpDir;
430
+ (0, _bunTest.beforeEach)(() => {
431
+ tmpDir = fs.mkdtempSync(path.join(os.tmpdir(), "sprinkles-builtin-test-"));
432
+ });
433
+ (0, _bunTest.afterEach)(() => {
434
+ fs.rmSync(tmpDir, {
435
+ recursive: true,
436
+ force: true
437
+ });
438
+ });
439
+ (0, _bunTest.test)("creates a new profile and returns id and name", async () => {
440
+ writeTestProfile(tmpDir, "default", "Default", {
441
+ name: "x"
442
+ });
443
+ const sprinkle = new _index.Sprinkle(SimpleSchema, tmpDir);
444
+ await sprinkle.loadProfile("default");
445
+ for (const action of (0, _index.getBuiltinActions)()) {
446
+ sprinkle.registerAction(action);
447
+ }
448
+ const result = await sprinkle.runAction("create-profile", {
449
+ name: "New Profile"
450
+ });
451
+ (0, _bunTest.expect)(result.success).toBe(true);
452
+ if (result.success) {
453
+ (0, _bunTest.expect)(result.data.name).toBe("New Profile");
454
+ (0, _bunTest.expect)(result.data.id).toBeDefined();
455
+ }
456
+ });
457
+ (0, _bunTest.test)("created profile file exists on disk", async () => {
458
+ writeTestProfile(tmpDir, "default", "Default", {
459
+ name: "x"
460
+ });
461
+ const sprinkle = new _index.Sprinkle(SimpleSchema, tmpDir);
462
+ await sprinkle.loadProfile("default");
463
+ for (const action of (0, _index.getBuiltinActions)()) {
464
+ sprinkle.registerAction(action);
465
+ }
466
+ const result = await sprinkle.runAction("create-profile", {
467
+ name: "Disk Profile"
468
+ });
469
+ (0, _bunTest.expect)(result.success).toBe(true);
470
+ if (result.success) {
471
+ const profilePath = path.join(tmpDir, "profiles", `${result.data.id}.json`);
472
+ (0, _bunTest.expect)(fs.existsSync(profilePath)).toBe(true);
473
+ }
474
+ });
475
+ (0, _bunTest.test)("create-profile does NOT switch the active profile", async () => {
476
+ writeTestProfile(tmpDir, "default", "Default", {
477
+ name: "x"
478
+ });
479
+ const sprinkle = new _index.Sprinkle(SimpleSchema, tmpDir);
480
+ await sprinkle.loadProfile("default");
481
+ for (const action of (0, _index.getBuiltinActions)()) {
482
+ sprinkle.registerAction(action);
483
+ }
484
+ await sprinkle.runAction("create-profile", {
485
+ name: "Another Profile"
486
+ });
487
+ (0, _bunTest.expect)(sprinkle.profileId).toBe("default");
488
+ });
489
+ (0, _bunTest.test)("create-profile with optional description stores it", async () => {
490
+ writeTestProfile(tmpDir, "default", "Default", {
491
+ name: "x"
492
+ });
493
+ const sprinkle = new _index.Sprinkle(SimpleSchema, tmpDir);
494
+ await sprinkle.loadProfile("default");
495
+ for (const action of (0, _index.getBuiltinActions)()) {
496
+ sprinkle.registerAction(action);
497
+ }
498
+ const result = await sprinkle.runAction("create-profile", {
499
+ name: "Described Profile",
500
+ description: "A detailed description"
501
+ });
502
+ (0, _bunTest.expect)(result.success).toBe(true);
503
+ if (result.success) {
504
+ const profilePath = path.join(tmpDir, "profiles", `${result.data.id}.json`);
505
+ const content = JSON.parse(fs.readFileSync(profilePath, "utf-8"));
506
+ (0, _bunTest.expect)(content.meta.description).toBe("A detailed description");
507
+ }
508
+ });
509
+ (0, _bunTest.test)("returns DUPLICATE_PROFILE error when name already exists", async () => {
510
+ writeTestProfile(tmpDir, "default", "Default", {
511
+ name: "x"
512
+ });
513
+ const sprinkle = new _index.Sprinkle(SimpleSchema, tmpDir);
514
+ await sprinkle.loadProfile("default");
515
+ for (const action of (0, _index.getBuiltinActions)()) {
516
+ sprinkle.registerAction(action);
517
+ }
518
+ const result = await sprinkle.runAction("create-profile", {
519
+ name: "Default"
520
+ });
521
+ (0, _bunTest.expect)(result.success).toBe(false);
522
+ if (!result.success) {
523
+ (0, _bunTest.expect)(result.error.code).toBe("DUPLICATE_PROFILE");
524
+ }
525
+ });
526
+ (0, _bunTest.test)("duplicate name check is case-insensitive", async () => {
527
+ writeTestProfile(tmpDir, "default", "Default", {
528
+ name: "x"
529
+ });
530
+ const sprinkle = new _index.Sprinkle(SimpleSchema, tmpDir);
531
+ await sprinkle.loadProfile("default");
532
+ for (const action of (0, _index.getBuiltinActions)()) {
533
+ sprinkle.registerAction(action);
534
+ }
535
+ const result = await sprinkle.runAction("create-profile", {
536
+ name: "DEFAULT"
537
+ });
538
+ (0, _bunTest.expect)(result.success).toBe(false);
539
+ if (!result.success) {
540
+ (0, _bunTest.expect)(result.error.code).toBe("DUPLICATE_PROFILE");
541
+ }
542
+ });
543
+ (0, _bunTest.test)("create-profile with initial settings writes them to disk", async () => {
544
+ writeTestProfile(tmpDir, "default", "Default", {
545
+ name: "x"
546
+ });
547
+ const sprinkle = new _index.Sprinkle(SimpleSchema, tmpDir);
548
+ await sprinkle.loadProfile("default");
549
+ for (const action of (0, _index.getBuiltinActions)()) {
550
+ sprinkle.registerAction(action);
551
+ }
552
+ const result = await sprinkle.runAction("create-profile", {
553
+ name: "Preset Profile",
554
+ settings: {
555
+ name: "preset-name"
556
+ }
557
+ });
558
+ (0, _bunTest.expect)(result.success).toBe(true);
559
+ if (result.success) {
560
+ const profilePath = path.join(tmpDir, "profiles", `${result.data.id}.json`);
561
+ const content = JSON.parse(fs.readFileSync(profilePath, "utf-8"));
562
+ (0, _bunTest.expect)(content.settings.name).toBe("preset-name");
563
+ }
564
+ });
565
+ });
566
+
567
+ // ---------------------------------------------------------------------------
568
+ // delete-profile
569
+ // ---------------------------------------------------------------------------
570
+
571
+ (0, _bunTest.describe)("delete-profile action", () => {
572
+ let tmpDir;
573
+ (0, _bunTest.beforeEach)(() => {
574
+ tmpDir = fs.mkdtempSync(path.join(os.tmpdir(), "sprinkles-builtin-test-"));
575
+ });
576
+ (0, _bunTest.afterEach)(() => {
577
+ fs.rmSync(tmpDir, {
578
+ recursive: true,
579
+ force: true
580
+ });
581
+ });
582
+ (0, _bunTest.test)("deletes a profile and returns deleted:true with id", async () => {
583
+ writeTestProfile(tmpDir, "alice", "Alice", {
584
+ name: "alice"
585
+ });
586
+ writeTestProfile(tmpDir, "bob", "Bob", {
587
+ name: "bob"
588
+ });
589
+ const sprinkle = new _index.Sprinkle(SimpleSchema, tmpDir);
590
+ await sprinkle.loadProfile("alice");
591
+ for (const action of (0, _index.getBuiltinActions)()) {
592
+ sprinkle.registerAction(action);
593
+ }
594
+ const result = await sprinkle.runAction("delete-profile", {
595
+ id: "bob"
596
+ });
597
+ (0, _bunTest.expect)(result.success).toBe(true);
598
+ if (result.success) {
599
+ (0, _bunTest.expect)(result.data.deleted).toBe(true);
600
+ (0, _bunTest.expect)(result.data.id).toBe("bob");
601
+ }
602
+ });
603
+ (0, _bunTest.test)("profile file is removed from disk after deletion", async () => {
604
+ writeTestProfile(tmpDir, "alice", "Alice", {
605
+ name: "alice"
606
+ });
607
+ writeTestProfile(tmpDir, "bob", "Bob", {
608
+ name: "bob"
609
+ });
610
+ const sprinkle = new _index.Sprinkle(SimpleSchema, tmpDir);
611
+ await sprinkle.loadProfile("alice");
612
+ for (const action of (0, _index.getBuiltinActions)()) {
613
+ sprinkle.registerAction(action);
614
+ }
615
+ await sprinkle.runAction("delete-profile", {
616
+ id: "bob"
617
+ });
618
+ (0, _bunTest.expect)(fs.existsSync(path.join(tmpDir, "profiles", "bob.json"))).toBe(false);
619
+ });
620
+ (0, _bunTest.test)("returns PROFILE_NOT_FOUND when deleting a non-existent profile", async () => {
621
+ writeTestProfile(tmpDir, "alice", "Alice", {
622
+ name: "alice"
623
+ });
624
+ writeTestProfile(tmpDir, "bob", "Bob", {
625
+ name: "bob"
626
+ });
627
+ const sprinkle = new _index.Sprinkle(SimpleSchema, tmpDir);
628
+ await sprinkle.loadProfile("alice");
629
+ for (const action of (0, _index.getBuiltinActions)()) {
630
+ sprinkle.registerAction(action);
631
+ }
632
+ const result = await sprinkle.runAction("delete-profile", {
633
+ id: "nobody"
634
+ });
635
+ (0, _bunTest.expect)(result.success).toBe(false);
636
+ if (!result.success) {
637
+ (0, _bunTest.expect)(result.error.code).toBe("PROFILE_NOT_FOUND");
638
+ }
639
+ });
640
+ (0, _bunTest.test)("returns CANNOT_DELETE_ONLY_PROFILE when only one profile exists", async () => {
641
+ writeTestProfile(tmpDir, "only", "Only", {
642
+ name: "x"
643
+ });
644
+ const sprinkle = new _index.Sprinkle(SimpleSchema, tmpDir);
645
+ await sprinkle.loadProfile("only");
646
+ for (const action of (0, _index.getBuiltinActions)()) {
647
+ sprinkle.registerAction(action);
648
+ }
649
+ const result = await sprinkle.runAction("delete-profile", {
650
+ id: "only"
651
+ });
652
+ (0, _bunTest.expect)(result.success).toBe(false);
653
+ if (!result.success) {
654
+ (0, _bunTest.expect)(result.error.code).toBe("CANNOT_DELETE_ONLY_PROFILE");
655
+ }
656
+ });
657
+ (0, _bunTest.test)("returns CANNOT_DELETE_ACTIVE_PROFILE when deleting the active profile", async () => {
658
+ writeTestProfile(tmpDir, "active", "Active", {
659
+ name: "x"
660
+ });
661
+ writeTestProfile(tmpDir, "other", "Other", {
662
+ name: "y"
663
+ });
664
+ const sprinkle = new _index.Sprinkle(SimpleSchema, tmpDir);
665
+ await sprinkle.loadProfile("active");
666
+ for (const action of (0, _index.getBuiltinActions)()) {
667
+ sprinkle.registerAction(action);
668
+ }
669
+ const result = await sprinkle.runAction("delete-profile", {
670
+ id: "active"
671
+ });
672
+ (0, _bunTest.expect)(result.success).toBe(false);
673
+ if (!result.success) {
674
+ (0, _bunTest.expect)(result.error.code).toBe("CANNOT_DELETE_ACTIVE_PROFILE");
675
+ }
676
+ });
677
+ });
678
+
679
+ // ---------------------------------------------------------------------------
680
+ // get-settings
681
+ // ---------------------------------------------------------------------------
682
+
683
+ (0, _bunTest.describe)("get-settings action", () => {
684
+ let tmpDir;
685
+ (0, _bunTest.beforeEach)(() => {
686
+ tmpDir = fs.mkdtempSync(path.join(os.tmpdir(), "sprinkles-builtin-test-"));
687
+ });
688
+ (0, _bunTest.afterEach)(() => {
689
+ fs.rmSync(tmpDir, {
690
+ recursive: true,
691
+ force: true
692
+ });
693
+ });
694
+ (0, _bunTest.test)("returns settings, profileId, and profileName", async () => {
695
+ const sprinkle = await makeSprinkle(tmpDir, "default", {
696
+ name: "Alice"
697
+ });
698
+ for (const action of (0, _index.getBuiltinActions)()) {
699
+ sprinkle.registerAction(action);
700
+ }
701
+ const result = await sprinkle.runAction("get-settings", {});
702
+ (0, _bunTest.expect)(result.success).toBe(true);
703
+ if (result.success) {
704
+ (0, _bunTest.expect)(result.data.profileId).toBe("default");
705
+ (0, _bunTest.expect)(result.data.profileName).toBe("Default");
706
+ (0, _bunTest.expect)(result.data.settings).toBeDefined();
707
+ }
708
+ });
709
+ (0, _bunTest.test)("returns masked settings by default", async () => {
710
+ const sprinkle = await makeSprinkle(tmpDir, "default", {
711
+ name: "Alice"
712
+ });
713
+ for (const action of (0, _index.getBuiltinActions)()) {
714
+ sprinkle.registerAction(action);
715
+ }
716
+ const result = await sprinkle.runAction("get-settings", {});
717
+ (0, _bunTest.expect)(result.success).toBe(true);
718
+ if (result.success) {
719
+ // For a schema without sensitive fields, settings pass through unchanged
720
+ (0, _bunTest.expect)(result.data.settings.name).toBe("Alice");
721
+ }
722
+ });
723
+ (0, _bunTest.test)("returns raw settings when includeSensitive is true", async () => {
724
+ const sprinkle = await makeSprinkle(tmpDir, "default", {
725
+ name: "raw-user"
726
+ });
727
+ for (const action of (0, _index.getBuiltinActions)()) {
728
+ sprinkle.registerAction(action);
729
+ }
730
+ const result = await sprinkle.runAction("get-settings", {
731
+ includeSensitive: true
732
+ });
733
+ (0, _bunTest.expect)(result.success).toBe(true);
734
+ if (result.success) {
735
+ (0, _bunTest.expect)(result.data.settings.name).toBe("raw-user");
736
+ }
737
+ });
738
+ (0, _bunTest.test)("returns same settings whether includeSensitive is false or not provided (no sensitive fields)", async () => {
739
+ const sprinkle = await makeSprinkle(tmpDir, "default", {
740
+ name: "same-user"
741
+ });
742
+ for (const action of (0, _index.getBuiltinActions)()) {
743
+ sprinkle.registerAction(action);
744
+ }
745
+ const [masked, raw] = await Promise.all([sprinkle.runAction("get-settings", {
746
+ includeSensitive: false
747
+ }), sprinkle.runAction("get-settings", {
748
+ includeSensitive: true
749
+ })]);
750
+ (0, _bunTest.expect)(masked.success).toBe(true);
751
+ (0, _bunTest.expect)(raw.success).toBe(true);
752
+ if (masked.success && raw.success) {
753
+ (0, _bunTest.expect)(masked.data.settings).toEqual(raw.data.settings);
754
+ }
755
+ });
756
+ (0, _bunTest.test)("settings match what was loaded from profile", async () => {
757
+ const sprinkle = await makeSprinkle(tmpDir, "prof", {
758
+ name: "expected-value"
759
+ });
760
+ for (const action of (0, _index.getBuiltinActions)()) {
761
+ sprinkle.registerAction(action);
762
+ }
763
+ const result = await sprinkle.runAction("get-settings", {
764
+ includeSensitive: true
765
+ });
766
+ (0, _bunTest.expect)(result.success).toBe(true);
767
+ if (result.success) {
768
+ (0, _bunTest.expect)(result.data.settings.name).toBe("expected-value");
769
+ }
770
+ });
771
+ });
772
+
773
+ // ---------------------------------------------------------------------------
774
+ // update-settings
775
+ // ---------------------------------------------------------------------------
776
+
777
+ (0, _bunTest.describe)("update-settings action", () => {
778
+ let tmpDir;
779
+ (0, _bunTest.beforeEach)(() => {
780
+ tmpDir = fs.mkdtempSync(path.join(os.tmpdir(), "sprinkles-builtin-test-"));
781
+ });
782
+ (0, _bunTest.afterEach)(() => {
783
+ fs.rmSync(tmpDir, {
784
+ recursive: true,
785
+ force: true
786
+ });
787
+ });
788
+ (0, _bunTest.test)("updates settings and returns masked settings with profileId", async () => {
789
+ const sprinkle = await makeSprinkle(tmpDir, "default", {
790
+ name: "old-name"
791
+ });
792
+ for (const action of (0, _index.getBuiltinActions)()) {
793
+ sprinkle.registerAction(action);
794
+ }
795
+ const result = await sprinkle.runAction("update-settings", {
796
+ settings: {
797
+ name: "new-name"
798
+ }
799
+ });
800
+ (0, _bunTest.expect)(result.success).toBe(true);
801
+ if (result.success) {
802
+ (0, _bunTest.expect)(result.data.settings.name).toBe("new-name");
803
+ (0, _bunTest.expect)(result.data.profileId).toBe("default");
804
+ }
805
+ });
806
+ (0, _bunTest.test)("update persists settings in memory", async () => {
807
+ const sprinkle = await makeSprinkle(tmpDir, "default", {
808
+ name: "before"
809
+ });
810
+ for (const action of (0, _index.getBuiltinActions)()) {
811
+ sprinkle.registerAction(action);
812
+ }
813
+ await sprinkle.runAction("update-settings", {
814
+ settings: {
815
+ name: "after"
816
+ }
817
+ });
818
+ (0, _bunTest.expect)(sprinkle.settings.name).toBe("after");
819
+ });
820
+ (0, _bunTest.test)("update persists settings to disk", async () => {
821
+ const sprinkle = await makeSprinkle(tmpDir, "default", {
822
+ name: "before"
823
+ });
824
+ for (const action of (0, _index.getBuiltinActions)()) {
825
+ sprinkle.registerAction(action);
826
+ }
827
+ await sprinkle.runAction("update-settings", {
828
+ settings: {
829
+ name: "persisted"
830
+ }
831
+ });
832
+
833
+ // Read the saved file to verify persistence
834
+ const profilePath = path.join(tmpDir, "profiles", "default.json");
835
+ const content = JSON.parse(fs.readFileSync(profilePath, "utf-8"));
836
+ (0, _bunTest.expect)(content.settings.name).toBe("persisted");
837
+ });
838
+ (0, _bunTest.test)("returns VALIDATION_ERROR for settings that violate schema", async () => {
839
+ const sprinkle = await makeSprinkle(tmpDir, "default", {
840
+ name: "valid"
841
+ });
842
+ for (const action of (0, _index.getBuiltinActions)()) {
843
+ sprinkle.registerAction(action);
844
+ }
845
+
846
+ // Removing required 'name' field should fail schema validation
847
+ const result = await sprinkle.runAction("update-settings", {
848
+ settings: {
849
+ name: 12345
850
+ } // name must be a string
851
+ });
852
+ (0, _bunTest.expect)(result.success).toBe(false);
853
+ if (!result.success) {
854
+ (0, _bunTest.expect)(result.error.code).toBe("VALIDATION_ERROR");
855
+ }
856
+ });
857
+ (0, _bunTest.test)("settings are not saved when validation fails", async () => {
858
+ const sprinkle = await makeSprinkle(tmpDir, "default", {
859
+ name: "original"
860
+ });
861
+ for (const action of (0, _index.getBuiltinActions)()) {
862
+ sprinkle.registerAction(action);
863
+ }
864
+ await sprinkle.runAction("update-settings", {
865
+ settings: {
866
+ name: 99
867
+ } // invalid: not a string
868
+ });
869
+
870
+ // Settings in memory should remain unchanged
871
+ (0, _bunTest.expect)(sprinkle.settings.name).toBe("original");
872
+ });
873
+ (0, _bunTest.test)("shallow merges settings - existing keys not in update are preserved", async () => {
874
+ // Use a schema with two optional keys to test merge behaviour
875
+ const TwoKeySchema = _typebox.Type.Object({
876
+ name: _typebox.Type.String(),
877
+ label: _typebox.Type.Optional(_typebox.Type.String())
878
+ });
879
+ writeTestProfile(tmpDir, "twokey", "TwoKey", {
880
+ name: "base",
881
+ label: "keep-me"
882
+ });
883
+ const sprinkle = new _index.Sprinkle(TwoKeySchema, tmpDir);
884
+ await sprinkle.loadProfile("twokey");
885
+ for (const action of (0, _index.getBuiltinActions)()) {
886
+ sprinkle.registerAction(action);
887
+ }
888
+ const result = await sprinkle.runAction("update-settings", {
889
+ settings: {
890
+ name: "updated"
891
+ }
892
+ });
893
+ (0, _bunTest.expect)(result.success).toBe(true);
894
+ if (result.success) {
895
+ (0, _bunTest.expect)(result.data.settings.name).toBe("updated");
896
+ (0, _bunTest.expect)(result.data.settings.label).toBe("keep-me");
897
+ }
898
+ });
899
+ });
900
+
901
+ // ---------------------------------------------------------------------------
902
+ // Sprinkle.getProfileById direct method tests
903
+ // ---------------------------------------------------------------------------
904
+
905
+ (0, _bunTest.describe)("Sprinkle.getProfileById", () => {
906
+ let tmpDir;
907
+ (0, _bunTest.beforeEach)(() => {
908
+ tmpDir = fs.mkdtempSync(path.join(os.tmpdir(), "sprinkles-builtin-test-"));
909
+ });
910
+ (0, _bunTest.afterEach)(() => {
911
+ fs.rmSync(tmpDir, {
912
+ recursive: true,
913
+ force: true
914
+ });
915
+ });
916
+ (0, _bunTest.test)("returns profile entry when id exists", () => {
917
+ writeTestProfile(tmpDir, "myid", "My Name", {
918
+ name: "x"
919
+ });
920
+ const sprinkle = new _index.Sprinkle(SimpleSchema, tmpDir);
921
+ const entry = sprinkle.getProfileById("myid");
922
+ (0, _bunTest.expect)(entry).toBeDefined();
923
+ (0, _bunTest.expect)(entry.id).toBe("myid");
924
+ (0, _bunTest.expect)(entry.meta.name).toBe("My Name");
925
+ });
926
+ (0, _bunTest.test)("returns undefined when id does not exist", () => {
927
+ writeTestProfile(tmpDir, "real", "Real", {
928
+ name: "x"
929
+ });
930
+ const sprinkle = new _index.Sprinkle(SimpleSchema, tmpDir);
931
+ (0, _bunTest.expect)(sprinkle.getProfileById("ghost")).toBeUndefined();
932
+ });
933
+ (0, _bunTest.test)("returns undefined when no profiles exist", () => {
934
+ const sprinkle = new _index.Sprinkle(SimpleSchema, tmpDir);
935
+ (0, _bunTest.expect)(sprinkle.getProfileById("anything")).toBeUndefined();
936
+ });
937
+ });
938
+
939
+ // ---------------------------------------------------------------------------
940
+ // Sprinkle.createProfileNonInteractive direct method tests
941
+ // ---------------------------------------------------------------------------
942
+
943
+ (0, _bunTest.describe)("Sprinkle.createProfileNonInteractive", () => {
944
+ let tmpDir;
945
+ (0, _bunTest.beforeEach)(() => {
946
+ tmpDir = fs.mkdtempSync(path.join(os.tmpdir(), "sprinkles-builtin-test-"));
947
+ });
948
+ (0, _bunTest.afterEach)(() => {
949
+ fs.rmSync(tmpDir, {
950
+ recursive: true,
951
+ force: true
952
+ });
953
+ });
954
+ (0, _bunTest.test)("creates a profile file and returns IProfileEntry", async () => {
955
+ const sprinkle = new _index.Sprinkle(SimpleSchema, tmpDir);
956
+ const entry = await sprinkle.createProfileNonInteractive("Test Profile");
957
+ (0, _bunTest.expect)(entry.id).toBeDefined();
958
+ (0, _bunTest.expect)(entry.meta.name).toBe("Test Profile");
959
+ const profilePath = path.join(tmpDir, "profiles", `${entry.id}.json`);
960
+ (0, _bunTest.expect)(fs.existsSync(profilePath)).toBe(true);
961
+ });
962
+ (0, _bunTest.test)("sanitizes name to form a valid id", async () => {
963
+ const sprinkle = new _index.Sprinkle(SimpleSchema, tmpDir);
964
+ const entry = await sprinkle.createProfileNonInteractive("My New Profile!");
965
+ // sanitized: "my-new-profile"
966
+ (0, _bunTest.expect)(entry.id).toBe("my-new-profile");
967
+ });
968
+ (0, _bunTest.test)("uses findAvailableId to avoid collisions", async () => {
969
+ const sprinkle = new _index.Sprinkle(SimpleSchema, tmpDir);
970
+ // "My Profile" sanitizes to "my-profile". Pre-create that file so
971
+ // findAvailableId must fall back to "my-profile-2".
972
+ writeTestProfile(tmpDir, "my-profile", "My Profile First", {
973
+ name: "x"
974
+ });
975
+ const entry = await sprinkle.createProfileNonInteractive("My Profile");
976
+ // "my-profile" is taken, so the entry id should become "my-profile-2"
977
+ (0, _bunTest.expect)(entry.id).toBe("my-profile-2");
978
+ });
979
+ (0, _bunTest.test)("throws DUPLICATE_PROFILE for same name (case-insensitive)", async () => {
980
+ writeTestProfile(tmpDir, "existing", "Existing Profile", {
981
+ name: "x"
982
+ });
983
+ const sprinkle = new _index.Sprinkle(SimpleSchema, tmpDir);
984
+ await (0, _bunTest.expect)(sprinkle.createProfileNonInteractive("existing profile")).rejects.toMatchObject({
985
+ code: "DUPLICATE_PROFILE"
986
+ });
987
+ });
988
+ (0, _bunTest.test)("stores optional description in meta", async () => {
989
+ const sprinkle = new _index.Sprinkle(SimpleSchema, tmpDir);
990
+ const entry = await sprinkle.createProfileNonInteractive("Described", "My description");
991
+ (0, _bunTest.expect)(entry.meta.description).toBe("My description");
992
+ const profilePath = path.join(tmpDir, "profiles", `${entry.id}.json`);
993
+ const content = JSON.parse(fs.readFileSync(profilePath, "utf-8"));
994
+ (0, _bunTest.expect)(content.meta.description).toBe("My description");
995
+ });
996
+ (0, _bunTest.test)("stores initial settings when provided", async () => {
997
+ const sprinkle = new _index.Sprinkle(SimpleSchema, tmpDir);
998
+ const entry = await sprinkle.createProfileNonInteractive("With Settings", undefined, {
999
+ name: "preset"
1000
+ });
1001
+ const profilePath = path.join(tmpDir, "profiles", `${entry.id}.json`);
1002
+ const content = JSON.parse(fs.readFileSync(profilePath, "utf-8"));
1003
+ (0, _bunTest.expect)(content.settings.name).toBe("preset");
1004
+ });
1005
+ (0, _bunTest.test)("does not change the active profile", async () => {
1006
+ writeTestProfile(tmpDir, "active", "Active", {
1007
+ name: "x"
1008
+ });
1009
+ const sprinkle = new _index.Sprinkle(SimpleSchema, tmpDir);
1010
+ await sprinkle.loadProfile("active");
1011
+ await sprinkle.createProfileNonInteractive("New One");
1012
+ (0, _bunTest.expect)(sprinkle.profileId).toBe("active");
1013
+ });
1014
+ });
1015
+
1016
+ // ---------------------------------------------------------------------------
1017
+ // Sprinkle.deleteProfileById direct method tests
1018
+ // ---------------------------------------------------------------------------
1019
+
1020
+ (0, _bunTest.describe)("Sprinkle.deleteProfileById", () => {
1021
+ let tmpDir;
1022
+ (0, _bunTest.beforeEach)(() => {
1023
+ tmpDir = fs.mkdtempSync(path.join(os.tmpdir(), "sprinkles-builtin-test-"));
1024
+ });
1025
+ (0, _bunTest.afterEach)(() => {
1026
+ fs.rmSync(tmpDir, {
1027
+ recursive: true,
1028
+ force: true
1029
+ });
1030
+ });
1031
+ (0, _bunTest.test)("removes the profile file from disk", () => {
1032
+ writeTestProfile(tmpDir, "keep", "Keep", {
1033
+ name: "x"
1034
+ });
1035
+ writeTestProfile(tmpDir, "remove", "Remove", {
1036
+ name: "y"
1037
+ });
1038
+ const sprinkle = new _index.Sprinkle(SimpleSchema, tmpDir);
1039
+ sprinkle.profileId = "keep";
1040
+ sprinkle.profileMeta = {
1041
+ name: "Keep",
1042
+ createdAt: "",
1043
+ updatedAt: ""
1044
+ };
1045
+ sprinkle.deleteProfileById("remove");
1046
+ (0, _bunTest.expect)(fs.existsSync(path.join(tmpDir, "profiles", "remove.json"))).toBe(false);
1047
+ (0, _bunTest.expect)(fs.existsSync(path.join(tmpDir, "profiles", "keep.json"))).toBe(true);
1048
+ });
1049
+ (0, _bunTest.test)("throws PROFILE_NOT_FOUND for unknown id", () => {
1050
+ writeTestProfile(tmpDir, "alpha", "Alpha", {
1051
+ name: "x"
1052
+ });
1053
+ writeTestProfile(tmpDir, "beta", "Beta", {
1054
+ name: "y"
1055
+ });
1056
+ const sprinkle = new _index.Sprinkle(SimpleSchema, tmpDir);
1057
+ sprinkle.profileId = "alpha";
1058
+ sprinkle.profileMeta = {
1059
+ name: "Alpha",
1060
+ createdAt: "",
1061
+ updatedAt: ""
1062
+ };
1063
+ (0, _bunTest.expect)(() => sprinkle.deleteProfileById("ghost")).toThrow();
1064
+ try {
1065
+ sprinkle.deleteProfileById("ghost");
1066
+ } catch (e) {
1067
+ (0, _bunTest.expect)(e.code).toBe("PROFILE_NOT_FOUND");
1068
+ }
1069
+ });
1070
+ (0, _bunTest.test)("throws CANNOT_DELETE_ONLY_PROFILE when only one profile exists", () => {
1071
+ writeTestProfile(tmpDir, "solo", "Solo", {
1072
+ name: "x"
1073
+ });
1074
+ const sprinkle = new _index.Sprinkle(SimpleSchema, tmpDir);
1075
+ sprinkle.profileId = "solo";
1076
+ sprinkle.profileMeta = {
1077
+ name: "Solo",
1078
+ createdAt: "",
1079
+ updatedAt: ""
1080
+ };
1081
+ (0, _bunTest.expect)(() => sprinkle.deleteProfileById("solo")).toThrow();
1082
+ try {
1083
+ sprinkle.deleteProfileById("solo");
1084
+ } catch (e) {
1085
+ (0, _bunTest.expect)(e.code).toBe("CANNOT_DELETE_ONLY_PROFILE");
1086
+ }
1087
+ });
1088
+ (0, _bunTest.test)("throws CANNOT_DELETE_ACTIVE_PROFILE when deleting the active profile", () => {
1089
+ writeTestProfile(tmpDir, "active", "Active", {
1090
+ name: "x"
1091
+ });
1092
+ writeTestProfile(tmpDir, "other", "Other", {
1093
+ name: "y"
1094
+ });
1095
+ const sprinkle = new _index.Sprinkle(SimpleSchema, tmpDir);
1096
+ sprinkle.profileId = "active";
1097
+ sprinkle.profileMeta = {
1098
+ name: "Active",
1099
+ createdAt: "",
1100
+ updatedAt: ""
1101
+ };
1102
+ (0, _bunTest.expect)(() => sprinkle.deleteProfileById("active")).toThrow();
1103
+ try {
1104
+ sprinkle.deleteProfileById("active");
1105
+ } catch (e) {
1106
+ (0, _bunTest.expect)(e.code).toBe("CANNOT_DELETE_ACTIVE_PROFILE");
1107
+ }
1108
+ });
1109
+ });
1110
+ //# sourceMappingURL=builtin-actions.test.js.map