@sundaeswap/sprinkles 0.7.0 → 0.8.1

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 (95) hide show
  1. package/README.md +178 -181
  2. package/dist/cjs/Sprinkle/__tests__/builtin-actions.test.js +4 -4
  3. package/dist/cjs/Sprinkle/__tests__/builtin-actions.test.js.map +1 -1
  4. package/dist/cjs/Sprinkle/__tests__/cli-adapter.test.js +25 -3
  5. package/dist/cjs/Sprinkle/__tests__/cli-adapter.test.js.map +1 -1
  6. package/dist/cjs/Sprinkle/__tests__/fill-in-struct.test.js +15 -1
  7. package/dist/cjs/Sprinkle/__tests__/fill-in-struct.test.js.map +1 -1
  8. package/dist/cjs/Sprinkle/__tests__/mcp-adapter.test.js +7 -9
  9. package/dist/cjs/Sprinkle/__tests__/mcp-adapter.test.js.map +1 -1
  10. package/dist/cjs/Sprinkle/__tests__/native-script.test.js +390 -0
  11. package/dist/cjs/Sprinkle/__tests__/native-script.test.js.map +1 -0
  12. package/dist/cjs/Sprinkle/__tests__/utility-actions.test.js +367 -0
  13. package/dist/cjs/Sprinkle/__tests__/utility-actions.test.js.map +1 -0
  14. package/dist/cjs/Sprinkle/actions/builtin/addressbook-actions.js +164 -0
  15. package/dist/cjs/Sprinkle/actions/builtin/addressbook-actions.js.map +1 -0
  16. package/dist/cjs/Sprinkle/actions/builtin/index.js +60 -3
  17. package/dist/cjs/Sprinkle/actions/builtin/index.js.map +1 -1
  18. package/dist/cjs/Sprinkle/actions/builtin/native-script.js +139 -0
  19. package/dist/cjs/Sprinkle/actions/builtin/native-script.js.map +1 -0
  20. package/dist/cjs/Sprinkle/actions/builtin/utility-actions.js +218 -0
  21. package/dist/cjs/Sprinkle/actions/builtin/utility-actions.js.map +1 -0
  22. package/dist/cjs/Sprinkle/actions/cli-adapter.js +20 -2
  23. package/dist/cjs/Sprinkle/actions/cli-adapter.js.map +1 -1
  24. package/dist/cjs/Sprinkle/actions/index.js +12 -0
  25. package/dist/cjs/Sprinkle/actions/index.js.map +1 -1
  26. package/dist/cjs/Sprinkle/actions/mcp-adapter.js +146 -4
  27. package/dist/cjs/Sprinkle/actions/mcp-adapter.js.map +1 -1
  28. package/dist/cjs/Sprinkle/index.js +282 -6
  29. package/dist/cjs/Sprinkle/index.js.map +1 -1
  30. package/dist/cjs/Sprinkle/schemas.js +17 -1
  31. package/dist/cjs/Sprinkle/schemas.js.map +1 -1
  32. package/dist/esm/Sprinkle/__tests__/builtin-actions.test.js +4 -4
  33. package/dist/esm/Sprinkle/__tests__/builtin-actions.test.js.map +1 -1
  34. package/dist/esm/Sprinkle/__tests__/cli-adapter.test.js +25 -3
  35. package/dist/esm/Sprinkle/__tests__/cli-adapter.test.js.map +1 -1
  36. package/dist/esm/Sprinkle/__tests__/fill-in-struct.test.js +15 -1
  37. package/dist/esm/Sprinkle/__tests__/fill-in-struct.test.js.map +1 -1
  38. package/dist/esm/Sprinkle/__tests__/mcp-adapter.test.js +7 -9
  39. package/dist/esm/Sprinkle/__tests__/mcp-adapter.test.js.map +1 -1
  40. package/dist/esm/Sprinkle/__tests__/native-script.test.js +388 -0
  41. package/dist/esm/Sprinkle/__tests__/native-script.test.js.map +1 -0
  42. package/dist/esm/Sprinkle/__tests__/utility-actions.test.js +365 -0
  43. package/dist/esm/Sprinkle/__tests__/utility-actions.test.js.map +1 -0
  44. package/dist/esm/Sprinkle/actions/builtin/addressbook-actions.js +159 -0
  45. package/dist/esm/Sprinkle/actions/builtin/addressbook-actions.js.map +1 -0
  46. package/dist/esm/Sprinkle/actions/builtin/index.js +8 -3
  47. package/dist/esm/Sprinkle/actions/builtin/index.js.map +1 -1
  48. package/dist/esm/Sprinkle/actions/builtin/native-script.js +133 -0
  49. package/dist/esm/Sprinkle/actions/builtin/native-script.js.map +1 -0
  50. package/dist/esm/Sprinkle/actions/builtin/utility-actions.js +213 -0
  51. package/dist/esm/Sprinkle/actions/builtin/utility-actions.js.map +1 -0
  52. package/dist/esm/Sprinkle/actions/cli-adapter.js +20 -2
  53. package/dist/esm/Sprinkle/actions/cli-adapter.js.map +1 -1
  54. package/dist/esm/Sprinkle/actions/index.js +1 -1
  55. package/dist/esm/Sprinkle/actions/index.js.map +1 -1
  56. package/dist/esm/Sprinkle/actions/mcp-adapter.js +145 -5
  57. package/dist/esm/Sprinkle/actions/mcp-adapter.js.map +1 -1
  58. package/dist/esm/Sprinkle/index.js +260 -9
  59. package/dist/esm/Sprinkle/index.js.map +1 -1
  60. package/dist/esm/Sprinkle/schemas.js +16 -0
  61. package/dist/esm/Sprinkle/schemas.js.map +1 -1
  62. package/dist/types/Sprinkle/actions/builtin/addressbook-actions.d.ts +50 -0
  63. package/dist/types/Sprinkle/actions/builtin/addressbook-actions.d.ts.map +1 -0
  64. package/dist/types/Sprinkle/actions/builtin/index.d.ts +6 -2
  65. package/dist/types/Sprinkle/actions/builtin/index.d.ts.map +1 -1
  66. package/dist/types/Sprinkle/actions/builtin/native-script.d.ts +27 -0
  67. package/dist/types/Sprinkle/actions/builtin/native-script.d.ts.map +1 -0
  68. package/dist/types/Sprinkle/actions/builtin/utility-actions.d.ts +48 -0
  69. package/dist/types/Sprinkle/actions/builtin/utility-actions.d.ts.map +1 -0
  70. package/dist/types/Sprinkle/actions/cli-adapter.d.ts.map +1 -1
  71. package/dist/types/Sprinkle/actions/index.d.ts +2 -1
  72. package/dist/types/Sprinkle/actions/index.d.ts.map +1 -1
  73. package/dist/types/Sprinkle/actions/mcp-adapter.d.ts +24 -0
  74. package/dist/types/Sprinkle/actions/mcp-adapter.d.ts.map +1 -1
  75. package/dist/types/Sprinkle/index.d.ts +5 -2
  76. package/dist/types/Sprinkle/index.d.ts.map +1 -1
  77. package/dist/types/Sprinkle/schemas.d.ts +72 -0
  78. package/dist/types/Sprinkle/schemas.d.ts.map +1 -1
  79. package/dist/types/tsconfig.build.tsbuildinfo +1 -1
  80. package/package.json +1 -1
  81. package/src/Sprinkle/__tests__/builtin-actions.test.ts +4 -4
  82. package/src/Sprinkle/__tests__/cli-adapter.test.ts +24 -3
  83. package/src/Sprinkle/__tests__/fill-in-struct.test.ts +23 -1
  84. package/src/Sprinkle/__tests__/mcp-adapter.test.ts +7 -5
  85. package/src/Sprinkle/__tests__/native-script.test.ts +341 -0
  86. package/src/Sprinkle/__tests__/utility-actions.test.ts +348 -0
  87. package/src/Sprinkle/actions/builtin/addressbook-actions.ts +168 -0
  88. package/src/Sprinkle/actions/builtin/index.ts +41 -2
  89. package/src/Sprinkle/actions/builtin/native-script.ts +165 -0
  90. package/src/Sprinkle/actions/builtin/utility-actions.ts +285 -0
  91. package/src/Sprinkle/actions/cli-adapter.ts +18 -2
  92. package/src/Sprinkle/actions/index.ts +2 -1
  93. package/src/Sprinkle/actions/mcp-adapter.ts +179 -4
  94. package/src/Sprinkle/index.ts +264 -3
  95. package/src/Sprinkle/schemas.ts +20 -0
@@ -17,9 +17,11 @@ export { UserCancelledError } from "./types.js";
17
17
  import { UserCancelledError } from "./types.js";
18
18
 
19
19
  // Re-export schemas from schemas.ts
20
- export { NetworkSchema, MultisigScriptModule, MultisigScript, ProviderSettingsSchema, WalletSettingsSchema } from "./schemas.js";
20
+ export { NetworkSchema, MultisigScriptModule, MultisigScript, NativeScriptInputSchema, NativeScriptsParam, ProviderSettingsSchema, WalletSettingsSchema } from "./schemas.js";
21
+ import { MultisigScript as MultisigScriptSchema } from "./schemas.js";
22
+
21
23
  // Import and re-export type guards
22
- import { isOptional, isImport, isArray, isBigInt, isLiteral, isObject, isRef, isString, isThis, isTuple, isUnion, isSensitive } from "./type-guards.js";
24
+ import { isOptional, isImport, isArray, isBigInt, isBoolean, isLiteral, isObject, isRef, isString, isThis, isTuple, isUnion, isSensitive, hasDefault, getDefault } from "./type-guards.js";
23
25
  export { isOptional, isImport, isArray, isBigInt, isBoolean, isInteger, isLiteral, isNumber, isObject, isRef, isString, isThis, isTuple, isUnion, isSensitive, isNull, isNullable, unwrapNullable, hasDefault, getDefault } from "./type-guards.js";
24
26
 
25
27
  // Import schemas for use in this file
@@ -39,14 +41,17 @@ import { promptObject, promptArray } from "./menus/index.js";
39
41
  import { formatPath } from "./utils/formatting.js";
40
42
 
41
43
  // Import and re-export action system
42
- import { ActionRegistry, ActionError, executeAction, detectMode, parseCliArgs, generateActionHelp, generateAppHelp, runCli, runMcp } from "./actions/index.js";
43
- export { ActionRegistry, ActionError, executeAction, detectMode, parseCliArgs, generateActionHelp, camelToKebab, kebabToCamel, coerceValue, parseArgvWithSchema, generateAppHelp, runCli, typeboxToJsonSchema, coerceMcpInput, getMcpSdk, createMcpServer, runMcp, getBuiltinActions, promptAndExecute } from "./actions/index.js";
44
+ import { ActionRegistry, ActionError, executeAction, detectMode, parseCliArgs, generateActionHelp, generateAppHelp, runCli, runMcp, promptAndExecute } from "./actions/index.js";
45
+ import { toNativeScript } from "./actions/index.js";
46
+ export { ActionRegistry, ActionError, executeAction, detectMode, parseCliArgs, generateActionHelp, camelToKebab, kebabToCamel, coerceValue, parseArgvWithSchema, generateAppHelp, runCli, typeboxToJsonSchema, coerceMcpInput, getMcpSdk, createMcpServer, runMcp, getBuiltinActions, promptAndExecute, toNativeScript, completeWithScripts } from "./actions/index.js";
47
+ import { mintToken, simpleSend, registerStakeScript } from "./actions/builtin/utility-actions.js";
44
48
  export class Sprinkle {
45
49
  constructor(type, storagePath, options) {
46
50
  _defineProperty(this, "storagePath", void 0);
47
51
  _defineProperty(this, "settings", {});
48
52
  _defineProperty(this, "type", void 0);
49
53
  _defineProperty(this, "defaults", {});
54
+ _defineProperty(this, "addressbook", {});
50
55
  _defineProperty(this, "options", void 0);
51
56
  _defineProperty(this, "profileId", "");
52
57
  _defineProperty(this, "profileMeta", {
@@ -129,6 +134,7 @@ export class Sprinkle {
129
134
  this.profileMeta = parsed.meta;
130
135
  this.settings = await this.decryptSettings(parsed.settings);
131
136
  this.defaults = parsed.defaults ?? {};
137
+ this.addressbook = parsed.addressbook ?? {};
132
138
  // Update active profile pointer
133
139
  fs.writeFileSync(Sprinkle.activeProfilePath(this.storagePath), id, "utf-8");
134
140
  }
@@ -148,7 +154,8 @@ export class Sprinkle {
148
154
  const jsonContent = JSON.stringify({
149
155
  meta: this.profileMeta,
150
156
  settings: settingsToSave,
151
- defaults: this.defaults
157
+ defaults: this.defaults,
158
+ addressbook: this.addressbook
152
159
  }, bigIntReplacer, 2);
153
160
  fs.writeFileSync(filePath, jsonContent, "utf-8");
154
161
  }
@@ -225,7 +232,8 @@ export class Sprinkle {
225
232
  updatedAt: now
226
233
  },
227
234
  settings: parsed.settings,
228
- defaults: parsed.defaults ?? {}
235
+ defaults: parsed.defaults ?? {},
236
+ addressbook: parsed.addressbook ?? {}
229
237
  };
230
238
  fs.mkdirSync(profilesDir, {
231
239
  recursive: true
@@ -300,7 +308,8 @@ export class Sprinkle {
300
308
  updatedAt: now
301
309
  },
302
310
  settings: settingsToSave,
303
- defaults: this.defaults
311
+ defaults: this.defaults,
312
+ addressbook: this.addressbook
304
313
  }, bigIntReplacer, 2);
305
314
  fs.writeFileSync(path.join(profilesDir, `${id}.json`), jsonContent, "utf-8");
306
315
  console.log(`Profile "${name}" created as a copy.`);
@@ -394,6 +403,10 @@ export class Sprinkle {
394
403
  value: -1
395
404
  });
396
405
  } else {
406
+ choices.push({
407
+ name: "Utilities",
408
+ value: -6
409
+ });
397
410
  choices.push({
398
411
  name: "Settings & Profiles",
399
412
  value: -5
@@ -417,6 +430,58 @@ export class Sprinkle {
417
430
  return;
418
431
  }
419
432
  const selection = selectionResult;
433
+ if (selection === -6) {
434
+ const utilitiesMenu = {
435
+ title: "Utilities",
436
+ items: [{
437
+ title: "Mint Token",
438
+ action: async () => {
439
+ const result = await promptAndExecute(this, mintToken);
440
+ if (!result.success) {
441
+ if (result.error.code === "USER_CANCELLED") return;
442
+ console.error(`\nError (${result.error.code}): ${result.error.message}\n`);
443
+ return;
444
+ }
445
+ const data = result.data;
446
+ console.log(`\nPolicy: ${data.policyId}\nToken: ${data.tokenName}\nAmount: ${data.amount}\n`);
447
+ const blaze = await Sprinkle.GetBlaze(this.settings.network, this.settings.provider, this.settings.wallet);
448
+ const tx = Core.Transaction.fromCbor(Core.TxCBOR(data.txCbor));
449
+ await this.TxDialog(blaze, tx);
450
+ }
451
+ }, {
452
+ title: "Simple Send",
453
+ action: async () => {
454
+ const result = await promptAndExecute(this, simpleSend);
455
+ if (!result.success) {
456
+ if (result.error.code === "USER_CANCELLED") return;
457
+ console.error(`\nError (${result.error.code}): ${result.error.message}\n`);
458
+ return;
459
+ }
460
+ const data = result.data;
461
+ const blaze = await Sprinkle.GetBlaze(this.settings.network, this.settings.provider, this.settings.wallet);
462
+ const tx = Core.Transaction.fromCbor(Core.TxCBOR(data.txCbor));
463
+ await this.TxDialog(blaze, tx);
464
+ }
465
+ }, {
466
+ title: "Register Stake Script",
467
+ action: async () => {
468
+ const result = await promptAndExecute(this, registerStakeScript);
469
+ if (!result.success) {
470
+ if (result.error.code === "USER_CANCELLED") return;
471
+ console.error(`\nError (${result.error.code}): ${result.error.message}\n`);
472
+ return;
473
+ }
474
+ const data = result.data;
475
+ const blaze = await Sprinkle.GetBlaze(this.settings.network, this.settings.provider, this.settings.wallet);
476
+ const tx = Core.Transaction.fromCbor(Core.TxCBOR(data.txCbor));
477
+ await this.TxDialog(blaze, tx);
478
+ }
479
+ }]
480
+ };
481
+ await this._showMenu(utilitiesMenu, false, [...path, "Utilities"], true);
482
+ await this._showMenu(menu, main, path, true);
483
+ return;
484
+ }
420
485
  if (selection === -5) {
421
486
  const settingsMenu = {
422
487
  title: "Settings & Profiles",
@@ -483,6 +548,113 @@ export class Sprinkle {
483
548
  action: async () => {
484
549
  await this.deleteProfile();
485
550
  }
551
+ }, {
552
+ title: "Addressbook",
553
+ items: [{
554
+ title: "View entries",
555
+ action: async () => {
556
+ const entries = Object.entries(this.addressbook);
557
+ if (entries.length === 0) {
558
+ console.log("Addressbook is empty.");
559
+ } else {
560
+ for (const [name, ms] of entries) {
561
+ const json = JSON.stringify(ms, bigIntReplacer, 2);
562
+ let hashStr = "unknown";
563
+ try {
564
+ hashStr = toNativeScript(ms).hash();
565
+ } catch {/* skip */}
566
+ console.log(colors.bold(name) + " " + colors.dim(hashStr));
567
+ console.log(json);
568
+ console.log();
569
+ }
570
+ }
571
+ await selectWithClear({
572
+ message: "Press Enter to continue...",
573
+ choices: [{
574
+ name: "Continue",
575
+ value: "continue"
576
+ }]
577
+ });
578
+ }
579
+ }, {
580
+ title: "Add entry",
581
+ action: async () => {
582
+ const name = await inputCancellable({
583
+ message: "Entry name:",
584
+ validate: v => v.trim().length > 0 ? true : "Name cannot be empty"
585
+ });
586
+ if (name === null) return;
587
+ if (this.addressbook[name]) {
588
+ const overwrite = await confirmCancellable({
589
+ message: `Entry "${name}" already exists. Overwrite?`,
590
+ default: false
591
+ });
592
+ if (!overwrite) return;
593
+ }
594
+ try {
595
+ const script = await this.FillInStruct(MultisigScriptSchema);
596
+ this.addressbook[name] = script;
597
+ this.saveSettings();
598
+ console.log(`Added "${name}" to addressbook.`);
599
+ } catch (e) {
600
+ if (e instanceof UserCancelledError) return;
601
+ throw e;
602
+ }
603
+ }
604
+ }, {
605
+ title: "Edit entry",
606
+ action: async () => {
607
+ const entries = Object.keys(this.addressbook);
608
+ if (entries.length === 0) {
609
+ console.log("Addressbook is empty.");
610
+ return;
611
+ }
612
+ const selected = await selectCancellable({
613
+ message: "Select entry to edit:",
614
+ choices: entries.map(n => ({
615
+ name: n,
616
+ value: n
617
+ }))
618
+ });
619
+ if (selected === null) return;
620
+ const editName = selected;
621
+ try {
622
+ const updated = await this.EditStruct(MultisigScriptSchema, this.addressbook[editName]);
623
+ this.addressbook[editName] = updated;
624
+ this.saveSettings();
625
+ console.log(`Updated "${editName}".`);
626
+ } catch (e) {
627
+ if (e instanceof UserCancelledError) return;
628
+ throw e;
629
+ }
630
+ }
631
+ }, {
632
+ title: "Delete entry",
633
+ action: async () => {
634
+ const entries = Object.keys(this.addressbook);
635
+ if (entries.length === 0) {
636
+ console.log("Addressbook is empty.");
637
+ return;
638
+ }
639
+ const delSelected = await selectCancellable({
640
+ message: "Select entry to delete:",
641
+ choices: entries.map(n => ({
642
+ name: n,
643
+ value: n
644
+ }))
645
+ });
646
+ if (delSelected === null) return;
647
+ const delName = delSelected;
648
+ const confirmed = await confirmCancellable({
649
+ message: `Delete "${delName}"?`,
650
+ default: false
651
+ });
652
+ if (!confirmed) return;
653
+ delete this.addressbook[delName];
654
+ this.saveSettings();
655
+ console.log(`Deleted "${delName}".`);
656
+ }
657
+ }]
486
658
  }]
487
659
  };
488
660
  await this._showMenu(settingsMenu, false, [...path, "Settings & Profiles"], true);
@@ -621,7 +793,8 @@ export class Sprinkle {
621
793
  const profileData = {
622
794
  meta,
623
795
  settings: initialSettings ?? {},
624
- defaults: {}
796
+ defaults: {},
797
+ addressbook: {}
625
798
  };
626
799
  fs.writeFileSync(path.join(profilesDir, `${id}.json`), JSON.stringify(profileData, bigIntReplacer, 2), "utf-8");
627
800
  return {
@@ -966,7 +1139,67 @@ export class Sprinkle {
966
1139
  if (!resolvedType) {
967
1140
  throw new Error(`Could not resolve type ${type["$ref"]} at ${path.join(".")}`);
968
1141
  }
969
- return this._fillInStruct(resolvedType, path, defs, def);
1142
+
1143
+ // Addressbook integration for MultisigScript fields
1144
+ if (type["$ref"] === "MultisigScript" && Object.keys(this.addressbook).length > 0) {
1145
+ const sourceChoice = await selectWithClear({
1146
+ message: "Select source for native script:",
1147
+ choices: [{
1148
+ name: "Enter manually",
1149
+ value: "manual"
1150
+ }, {
1151
+ name: "Select from addressbook",
1152
+ value: "addressbook"
1153
+ }]
1154
+ });
1155
+ if (sourceChoice === null) throw new UserCancelledError();
1156
+ if (sourceChoice === "addressbook") {
1157
+ const entries = Object.entries(this.addressbook);
1158
+ const abChoices = entries.map(([name, ms]) => {
1159
+ let hashStr = "";
1160
+ try {
1161
+ hashStr = " " + colors.dim(toNativeScript(ms).hash());
1162
+ } catch {/* skip */}
1163
+ return {
1164
+ name: name + hashStr,
1165
+ value: name
1166
+ };
1167
+ });
1168
+ const selected = await selectWithClear({
1169
+ message: "Select addressbook entry:",
1170
+ choices: abChoices
1171
+ });
1172
+ if (selected === null) throw new UserCancelledError();
1173
+ return this.addressbook[selected];
1174
+ }
1175
+ }
1176
+ const result = await this._fillInStruct(resolvedType, path, defs, def);
1177
+
1178
+ // Offer to save manually entered MultisigScript to addressbook
1179
+ if (type["$ref"] === "MultisigScript" && result !== undefined) {
1180
+ const shouldSave = await selectWithClear({
1181
+ message: "Save this script to the addressbook?",
1182
+ choices: [{
1183
+ name: "No",
1184
+ value: false
1185
+ }, {
1186
+ name: "Yes",
1187
+ value: true
1188
+ }]
1189
+ });
1190
+ if (shouldSave) {
1191
+ const entryName = await inputCancellable({
1192
+ message: "Addressbook entry name:",
1193
+ validate: v => v.trim().length > 0 ? true : "Name cannot be empty"
1194
+ });
1195
+ if (entryName !== null) {
1196
+ this.addressbook[entryName] = result;
1197
+ this.saveSettings();
1198
+ console.log(`Saved "${entryName}" to addressbook.`);
1199
+ }
1200
+ }
1201
+ }
1202
+ return result;
970
1203
  }
971
1204
  if (isOptional(type)) {
972
1205
  const pathDisplay = formatPath(path) || "value";
@@ -1111,6 +1344,24 @@ export class Sprinkle {
1111
1344
  }
1112
1345
  return BigInt(answer);
1113
1346
  }
1347
+ if (isBoolean(type)) {
1348
+ const pathDisplay = formatPath(path) || "value";
1349
+ const answer = await selectWithClear({
1350
+ message: Sprinkle.ExtractMessage(type, `${pathDisplay}?`),
1351
+ choices: [{
1352
+ name: "Yes",
1353
+ value: true
1354
+ }, {
1355
+ name: "No",
1356
+ value: false
1357
+ }],
1358
+ default: def !== undefined ? def : hasDefault(type) ? getDefault(type) : undefined
1359
+ });
1360
+ if (answer === null) {
1361
+ throw new UserCancelledError();
1362
+ }
1363
+ return answer;
1364
+ }
1114
1365
  if (isLiteral(type)) {
1115
1366
  return type.const;
1116
1367
  }