@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.
- package/README.md +178 -181
- package/dist/cjs/Sprinkle/__tests__/builtin-actions.test.js +4 -4
- package/dist/cjs/Sprinkle/__tests__/builtin-actions.test.js.map +1 -1
- package/dist/cjs/Sprinkle/__tests__/cli-adapter.test.js +25 -3
- package/dist/cjs/Sprinkle/__tests__/cli-adapter.test.js.map +1 -1
- package/dist/cjs/Sprinkle/__tests__/fill-in-struct.test.js +15 -1
- package/dist/cjs/Sprinkle/__tests__/fill-in-struct.test.js.map +1 -1
- package/dist/cjs/Sprinkle/__tests__/mcp-adapter.test.js +7 -9
- package/dist/cjs/Sprinkle/__tests__/mcp-adapter.test.js.map +1 -1
- package/dist/cjs/Sprinkle/__tests__/native-script.test.js +390 -0
- package/dist/cjs/Sprinkle/__tests__/native-script.test.js.map +1 -0
- package/dist/cjs/Sprinkle/__tests__/utility-actions.test.js +367 -0
- package/dist/cjs/Sprinkle/__tests__/utility-actions.test.js.map +1 -0
- package/dist/cjs/Sprinkle/actions/builtin/addressbook-actions.js +164 -0
- package/dist/cjs/Sprinkle/actions/builtin/addressbook-actions.js.map +1 -0
- package/dist/cjs/Sprinkle/actions/builtin/index.js +60 -3
- package/dist/cjs/Sprinkle/actions/builtin/index.js.map +1 -1
- package/dist/cjs/Sprinkle/actions/builtin/native-script.js +139 -0
- package/dist/cjs/Sprinkle/actions/builtin/native-script.js.map +1 -0
- package/dist/cjs/Sprinkle/actions/builtin/utility-actions.js +218 -0
- package/dist/cjs/Sprinkle/actions/builtin/utility-actions.js.map +1 -0
- package/dist/cjs/Sprinkle/actions/cli-adapter.js +20 -2
- package/dist/cjs/Sprinkle/actions/cli-adapter.js.map +1 -1
- package/dist/cjs/Sprinkle/actions/index.js +12 -0
- package/dist/cjs/Sprinkle/actions/index.js.map +1 -1
- package/dist/cjs/Sprinkle/actions/mcp-adapter.js +146 -4
- package/dist/cjs/Sprinkle/actions/mcp-adapter.js.map +1 -1
- package/dist/cjs/Sprinkle/index.js +282 -6
- package/dist/cjs/Sprinkle/index.js.map +1 -1
- package/dist/cjs/Sprinkle/schemas.js +17 -1
- package/dist/cjs/Sprinkle/schemas.js.map +1 -1
- package/dist/esm/Sprinkle/__tests__/builtin-actions.test.js +4 -4
- package/dist/esm/Sprinkle/__tests__/builtin-actions.test.js.map +1 -1
- package/dist/esm/Sprinkle/__tests__/cli-adapter.test.js +25 -3
- package/dist/esm/Sprinkle/__tests__/cli-adapter.test.js.map +1 -1
- package/dist/esm/Sprinkle/__tests__/fill-in-struct.test.js +15 -1
- package/dist/esm/Sprinkle/__tests__/fill-in-struct.test.js.map +1 -1
- package/dist/esm/Sprinkle/__tests__/mcp-adapter.test.js +7 -9
- package/dist/esm/Sprinkle/__tests__/mcp-adapter.test.js.map +1 -1
- package/dist/esm/Sprinkle/__tests__/native-script.test.js +388 -0
- package/dist/esm/Sprinkle/__tests__/native-script.test.js.map +1 -0
- package/dist/esm/Sprinkle/__tests__/utility-actions.test.js +365 -0
- package/dist/esm/Sprinkle/__tests__/utility-actions.test.js.map +1 -0
- package/dist/esm/Sprinkle/actions/builtin/addressbook-actions.js +159 -0
- package/dist/esm/Sprinkle/actions/builtin/addressbook-actions.js.map +1 -0
- package/dist/esm/Sprinkle/actions/builtin/index.js +8 -3
- package/dist/esm/Sprinkle/actions/builtin/index.js.map +1 -1
- package/dist/esm/Sprinkle/actions/builtin/native-script.js +133 -0
- package/dist/esm/Sprinkle/actions/builtin/native-script.js.map +1 -0
- package/dist/esm/Sprinkle/actions/builtin/utility-actions.js +213 -0
- package/dist/esm/Sprinkle/actions/builtin/utility-actions.js.map +1 -0
- package/dist/esm/Sprinkle/actions/cli-adapter.js +20 -2
- package/dist/esm/Sprinkle/actions/cli-adapter.js.map +1 -1
- package/dist/esm/Sprinkle/actions/index.js +1 -1
- package/dist/esm/Sprinkle/actions/index.js.map +1 -1
- package/dist/esm/Sprinkle/actions/mcp-adapter.js +145 -5
- package/dist/esm/Sprinkle/actions/mcp-adapter.js.map +1 -1
- package/dist/esm/Sprinkle/index.js +260 -9
- package/dist/esm/Sprinkle/index.js.map +1 -1
- package/dist/esm/Sprinkle/schemas.js +16 -0
- package/dist/esm/Sprinkle/schemas.js.map +1 -1
- package/dist/types/Sprinkle/actions/builtin/addressbook-actions.d.ts +50 -0
- package/dist/types/Sprinkle/actions/builtin/addressbook-actions.d.ts.map +1 -0
- package/dist/types/Sprinkle/actions/builtin/index.d.ts +6 -2
- package/dist/types/Sprinkle/actions/builtin/index.d.ts.map +1 -1
- package/dist/types/Sprinkle/actions/builtin/native-script.d.ts +27 -0
- package/dist/types/Sprinkle/actions/builtin/native-script.d.ts.map +1 -0
- package/dist/types/Sprinkle/actions/builtin/utility-actions.d.ts +48 -0
- package/dist/types/Sprinkle/actions/builtin/utility-actions.d.ts.map +1 -0
- package/dist/types/Sprinkle/actions/cli-adapter.d.ts.map +1 -1
- package/dist/types/Sprinkle/actions/index.d.ts +2 -1
- package/dist/types/Sprinkle/actions/index.d.ts.map +1 -1
- package/dist/types/Sprinkle/actions/mcp-adapter.d.ts +24 -0
- package/dist/types/Sprinkle/actions/mcp-adapter.d.ts.map +1 -1
- package/dist/types/Sprinkle/index.d.ts +5 -2
- package/dist/types/Sprinkle/index.d.ts.map +1 -1
- package/dist/types/Sprinkle/schemas.d.ts +72 -0
- package/dist/types/Sprinkle/schemas.d.ts.map +1 -1
- package/dist/types/tsconfig.build.tsbuildinfo +1 -1
- package/package.json +1 -1
- package/src/Sprinkle/__tests__/builtin-actions.test.ts +4 -4
- package/src/Sprinkle/__tests__/cli-adapter.test.ts +24 -3
- package/src/Sprinkle/__tests__/fill-in-struct.test.ts +23 -1
- package/src/Sprinkle/__tests__/mcp-adapter.test.ts +7 -5
- package/src/Sprinkle/__tests__/native-script.test.ts +341 -0
- package/src/Sprinkle/__tests__/utility-actions.test.ts +348 -0
- package/src/Sprinkle/actions/builtin/addressbook-actions.ts +168 -0
- package/src/Sprinkle/actions/builtin/index.ts +41 -2
- package/src/Sprinkle/actions/builtin/native-script.ts +165 -0
- package/src/Sprinkle/actions/builtin/utility-actions.ts +285 -0
- package/src/Sprinkle/actions/cli-adapter.ts +18 -2
- package/src/Sprinkle/actions/index.ts +2 -1
- package/src/Sprinkle/actions/mcp-adapter.ts +179 -4
- package/src/Sprinkle/index.ts +264 -3
- package/src/Sprinkle/schemas.ts +20 -0
package/README.md
CHANGED
|
@@ -2,16 +2,41 @@
|
|
|
2
2
|
|
|
3
3
|
> **Note:** This is an early release (v0.x). The API may change between minor versions as we refine the library based on community feedback.
|
|
4
4
|
|
|
5
|
-
A TypeScript library for building
|
|
5
|
+
A TypeScript library for building action-centric CLI applications with TypeBox schema validation. Define your actions once, and Sprinkles exposes them through three facades: an interactive **TUI**, a **CLI** with auto-generated flags and help, and an **MCP** server for AI agent integration.
|
|
6
|
+
|
|
7
|
+
## Architecture
|
|
8
|
+
|
|
9
|
+
Sprinkles follows an **action-centric** design. The core building block is an `IAction` — a typed, self-describing unit of work with input/output schemas:
|
|
10
|
+
|
|
11
|
+
```
|
|
12
|
+
┌──────────────┐
|
|
13
|
+
│ Actions │ ← define once
|
|
14
|
+
│ (IAction) │
|
|
15
|
+
└──────┬───────┘
|
|
16
|
+
│
|
|
17
|
+
┌────────────┼────────────┐
|
|
18
|
+
▼ ▼ ▼
|
|
19
|
+
┌─────────┐ ┌─────────┐ ┌─────────┐
|
|
20
|
+
│ TUI │ │ CLI │ │ MCP │ ← three facades
|
|
21
|
+
│ (menu) │ │ (flags) │ │ (tools) │
|
|
22
|
+
└─────────┘ └─────────┘ └─────────┘
|
|
23
|
+
```
|
|
24
|
+
|
|
25
|
+
- **TUI** — Interactive menu-driven interface. Users select actions from a menu, and Sprinkles auto-generates prompts from input schemas.
|
|
26
|
+
- **CLI** — Non-interactive command execution. Actions become subcommands with auto-generated `--flags` from input schemas and structured JSON output.
|
|
27
|
+
- **MCP** — Model Context Protocol server. Actions are exposed as tools that AI agents can discover and call with typed JSON input/output.
|
|
28
|
+
|
|
29
|
+
`Sprinkle.run()` detects the mode from `process.argv` and dispatches automatically.
|
|
6
30
|
|
|
7
31
|
## Features
|
|
8
32
|
|
|
9
|
-
- **
|
|
10
|
-
- **
|
|
11
|
-
- **
|
|
12
|
-
- **
|
|
33
|
+
- **Action-centric**: Define actions with TypeBox input/output schemas; get TUI, CLI, and MCP for free
|
|
34
|
+
- **Schema-driven UI**: Automatic prompt generation from TypeBox schemas
|
|
35
|
+
- **Multi-profile support**: Multiple named profiles with independent settings
|
|
36
|
+
- **Persistent settings**: JSON-based storage with BigInt support and optional encryption
|
|
37
|
+
- **14 built-in actions**: Profile management, settings, wallet operations, and transaction handling
|
|
13
38
|
- **Cardano integration**: Built-in helpers for Blaze SDK wallet and provider management
|
|
14
|
-
- **
|
|
39
|
+
- **Type-safe**: Full TypeScript support with type inference from schemas
|
|
15
40
|
|
|
16
41
|
## Installation
|
|
17
42
|
|
|
@@ -19,241 +44,213 @@ A TypeScript library for building interactive CLI menus and TUI applications wit
|
|
|
19
44
|
npm install @sundaeswap/sprinkles
|
|
20
45
|
```
|
|
21
46
|
|
|
47
|
+
Optional peer dependencies:
|
|
48
|
+
- `@blaze-cardano/sdk` + `@blaze-cardano/query` — for wallet and transaction actions
|
|
49
|
+
- `@modelcontextprotocol/sdk` — for MCP mode
|
|
50
|
+
|
|
22
51
|
## Quick Start
|
|
23
52
|
|
|
24
53
|
```typescript
|
|
25
|
-
import {
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
54
|
+
import { Type } from "@sinclair/typebox";
|
|
55
|
+
import type { TSchema } from "@sinclair/typebox";
|
|
56
|
+
import {
|
|
57
|
+
Sprinkle,
|
|
58
|
+
promptAndExecute,
|
|
59
|
+
getBuiltinActions,
|
|
60
|
+
NetworkSchema,
|
|
61
|
+
ProviderSettingsSchema,
|
|
62
|
+
WalletSettingsSchema,
|
|
63
|
+
} from "@sundaeswap/sprinkles";
|
|
64
|
+
import type { AnyAction, IAction, IMenu } from "@sundaeswap/sprinkles";
|
|
65
|
+
|
|
66
|
+
// 1. Define your settings schema
|
|
67
|
+
const AppSettings = Type.Object({
|
|
68
|
+
network: NetworkSchema,
|
|
69
|
+
provider: ProviderSettingsSchema,
|
|
70
|
+
wallet: WalletSettingsSchema,
|
|
34
71
|
});
|
|
35
72
|
|
|
36
|
-
//
|
|
37
|
-
const
|
|
73
|
+
// 2. Define a custom action
|
|
74
|
+
const greetAction: IAction<
|
|
75
|
+
{ name: string },
|
|
76
|
+
{ greeting: string },
|
|
77
|
+
TSchema
|
|
78
|
+
> = {
|
|
79
|
+
name: "greet",
|
|
80
|
+
description: "Say hello to someone.",
|
|
81
|
+
category: "app",
|
|
82
|
+
inputSchema: Type.Object({
|
|
83
|
+
name: Type.String({ description: "Person to greet" }),
|
|
84
|
+
}),
|
|
85
|
+
outputSchema: Type.Object({
|
|
86
|
+
greeting: Type.String(),
|
|
87
|
+
}),
|
|
88
|
+
execute: async (input) => ({
|
|
89
|
+
greeting: `Hello, ${input.name}!`,
|
|
90
|
+
}),
|
|
91
|
+
};
|
|
38
92
|
|
|
39
|
-
// Define
|
|
40
|
-
const
|
|
41
|
-
title: "
|
|
93
|
+
// 3. Define a TUI menu
|
|
94
|
+
const menu: IMenu<typeof AppSettings> = {
|
|
95
|
+
title: "My App",
|
|
42
96
|
items: [
|
|
43
97
|
{
|
|
44
|
-
title: "
|
|
98
|
+
title: "Greet someone",
|
|
45
99
|
action: async (sprinkle) => {
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
100
|
+
const result = await promptAndExecute(sprinkle, greetAction);
|
|
101
|
+
if (result.success) {
|
|
102
|
+
console.log(result.data.greeting);
|
|
103
|
+
} else if (result.error.code !== "USER_CANCELLED") {
|
|
104
|
+
console.error("Error:", result.error.message);
|
|
105
|
+
}
|
|
106
|
+
},
|
|
107
|
+
},
|
|
108
|
+
],
|
|
50
109
|
};
|
|
51
110
|
|
|
52
|
-
//
|
|
53
|
-
await
|
|
111
|
+
// 4. Run — mode is detected automatically
|
|
112
|
+
await Sprinkle.run({
|
|
113
|
+
type: AppSettings,
|
|
114
|
+
storagePath: `${process.env["HOME"]}/.config/my-app`,
|
|
115
|
+
menu,
|
|
116
|
+
actions: [
|
|
117
|
+
greetAction as unknown as AnyAction<typeof AppSettings>,
|
|
118
|
+
...getBuiltinActions<typeof AppSettings>(),
|
|
119
|
+
],
|
|
120
|
+
});
|
|
54
121
|
```
|
|
55
122
|
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
### Core Classes
|
|
123
|
+
This single entry point gives you:
|
|
59
124
|
|
|
60
|
-
|
|
125
|
+
```bash
|
|
126
|
+
# TUI mode (interactive)
|
|
127
|
+
my-app
|
|
61
128
|
|
|
62
|
-
|
|
129
|
+
# CLI mode
|
|
130
|
+
my-app greet --name Alice
|
|
131
|
+
my-app list-profiles
|
|
132
|
+
my-app get-settings
|
|
63
133
|
|
|
64
|
-
|
|
134
|
+
# MCP mode (AI agent)
|
|
135
|
+
my-app --mcp
|
|
65
136
|
|
|
66
|
-
|
|
67
|
-
|
|
137
|
+
# Help
|
|
138
|
+
my-app --help
|
|
139
|
+
my-app greet --help
|
|
68
140
|
```
|
|
69
141
|
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
- `Sprinkle.New<S>(type: S, storagePath: string): Promise<Sprinkle<S>>` - Create and initialize a new Sprinkle instance
|
|
73
|
-
- `Sprinkle.GetProvider(network, settings): Provider` - Create a Cardano provider instance
|
|
74
|
-
- `Sprinkle.GetWallet(settings, provider): Promise<Wallet>` - Create a Cardano wallet instance
|
|
75
|
-
- `Sprinkle.GetBlaze(network, providerSettings, walletSettings): Promise<Blaze>` - Create a Blaze SDK instance
|
|
76
|
-
- `Sprinkle.SettingsPath(storagePath: string): string` - Get the settings file path
|
|
77
|
-
|
|
78
|
-
##### Instance Methods
|
|
142
|
+
## Actions
|
|
79
143
|
|
|
80
|
-
|
|
81
|
-
- `EditStruct<U>(type: U, current: TExact<U>): Promise<TExact<U>>` - Interactive editor for schema-based structures
|
|
82
|
-
- `FillInStruct<U>(type: U, def?: TExact<U>): Promise<TExact<U>>` - Interactive form to fill in a structure
|
|
83
|
-
- `TxDialog(blaze, tx): Promise<void>` - Display transaction dialog with sign/submit options
|
|
84
|
-
- `saveSettings(): void` - Persist current settings to disk
|
|
85
|
-
- `LoadSettings(type, storagePath): Promise<void>` - Load settings from disk
|
|
144
|
+
### Defining Actions
|
|
86
145
|
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
#### `IMenu<S>`
|
|
90
|
-
|
|
91
|
-
Defines a menu structure:
|
|
146
|
+
An action is an object implementing `IAction<TInput, TOutput, TSettings>`:
|
|
92
147
|
|
|
93
148
|
```typescript
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
149
|
+
const myAction: IAction<
|
|
150
|
+
{ url: string; timeout?: number },
|
|
151
|
+
{ status: number },
|
|
152
|
+
TSchema
|
|
153
|
+
> = {
|
|
154
|
+
name: "check-health",
|
|
155
|
+
description: "Check if a service is healthy.",
|
|
156
|
+
category: "ops",
|
|
157
|
+
inputSchema: Type.Object({
|
|
158
|
+
url: Type.String({ description: "Service URL" }),
|
|
159
|
+
timeout: Type.Optional(Type.Number({ description: "Timeout in ms", default: 5000 })),
|
|
160
|
+
}),
|
|
161
|
+
outputSchema: Type.Object({
|
|
162
|
+
status: Type.Number(),
|
|
163
|
+
}),
|
|
164
|
+
execute: async (input, context) => {
|
|
165
|
+
// context.settings gives you the current profile's settings
|
|
166
|
+
// context.sprinkle gives you the Sprinkle instance
|
|
167
|
+
const res = await fetch(input.url, { signal: AbortSignal.timeout(input.timeout ?? 5000) });
|
|
168
|
+
return { status: res.status };
|
|
169
|
+
},
|
|
170
|
+
};
|
|
98
171
|
```
|
|
99
172
|
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
173
|
+
### Built-in Actions
|
|
174
|
+
|
|
175
|
+
Sprinkles includes 14 built-in actions available via `getBuiltinActions()`:
|
|
176
|
+
|
|
177
|
+
| Category | Action | Description |
|
|
178
|
+
|----------|--------|-------------|
|
|
179
|
+
| sprinkles | `list-profiles` | List all profiles |
|
|
180
|
+
| sprinkles | `get-profile` | Get profile metadata and settings |
|
|
181
|
+
| sprinkles | `set-profile` | Switch active profile |
|
|
182
|
+
| sprinkles | `create-profile` | Create a new profile |
|
|
183
|
+
| sprinkles | `delete-profile` | Delete a profile |
|
|
184
|
+
| sprinkles | `get-settings` | Get current settings |
|
|
185
|
+
| sprinkles | `update-settings` | Update settings |
|
|
186
|
+
| wallet | `get-wallet-address` | Get wallet address |
|
|
187
|
+
| wallet | `get-wallet-balance` | Get ADA and token balances |
|
|
188
|
+
| wallet | `get-wallet-utxos` | Get UTxO set |
|
|
189
|
+
| wallet | `sign-transaction` | Sign a transaction (hot wallet only) |
|
|
190
|
+
| wallet | `submit-transaction` | Submit a signed transaction |
|
|
191
|
+
| wallet | `sign-and-submit` | Sign and submit in one step |
|
|
192
|
+
| transaction | `decode-transaction` | Decode transaction CBOR |
|
|
193
|
+
|
|
194
|
+
### Running Actions Programmatically
|
|
103
195
|
|
|
104
196
|
```typescript
|
|
105
|
-
|
|
106
|
-
title: string;
|
|
107
|
-
action: (sprinkle: Sprinkle<S>) => Promise<Sprinkle<S> | void>;
|
|
108
|
-
}
|
|
109
|
-
```
|
|
110
|
-
|
|
111
|
-
#### `TMenuItem<S>`
|
|
112
|
-
|
|
113
|
-
A menu item can be either an action or a submenu:
|
|
197
|
+
import { executeAction } from "@sundaeswap/sprinkles";
|
|
114
198
|
|
|
115
|
-
|
|
116
|
-
|
|
199
|
+
const result = await executeAction(myAction, { url: "https://example.com" }, context);
|
|
200
|
+
if (result.success) {
|
|
201
|
+
console.log(result.data.status);
|
|
202
|
+
} else {
|
|
203
|
+
console.error(result.error.code, result.error.message);
|
|
204
|
+
}
|
|
117
205
|
```
|
|
118
206
|
|
|
119
|
-
|
|
207
|
+
## Built-in Schemas
|
|
120
208
|
|
|
121
|
-
|
|
209
|
+
Sprinkles exports common Cardano schemas for use in your settings:
|
|
122
210
|
|
|
123
|
-
|
|
211
|
+
### `NetworkSchema`
|
|
124
212
|
|
|
125
213
|
```typescript
|
|
126
|
-
Type.Union([
|
|
127
|
-
Type.Literal("mainnet"),
|
|
128
|
-
Type.Literal("preview"),
|
|
129
|
-
Type.Literal("preprod")
|
|
130
|
-
])
|
|
214
|
+
Type.Union([Type.Literal("mainnet"), Type.Literal("preview"), Type.Literal("preprod")])
|
|
131
215
|
```
|
|
132
216
|
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
Cardano provider configuration:
|
|
217
|
+
### `ProviderSettingsSchema`
|
|
136
218
|
|
|
137
219
|
```typescript
|
|
138
220
|
Type.Union([
|
|
139
221
|
Type.Object({
|
|
140
222
|
type: Type.Literal("blockfrost"),
|
|
141
|
-
projectId: Type.String({ minLength: 1, title: "Blockfrost Project ID" })
|
|
223
|
+
projectId: Type.String({ minLength: 1, title: "Blockfrost Project ID" }),
|
|
142
224
|
}),
|
|
143
225
|
Type.Object({
|
|
144
226
|
type: Type.Literal("maestro"),
|
|
145
|
-
apiKey: Type.String({ minLength: 1, title: "Maestro API Key" })
|
|
146
|
-
})
|
|
227
|
+
apiKey: Type.String({ minLength: 1, title: "Maestro API Key" }),
|
|
228
|
+
}),
|
|
147
229
|
])
|
|
148
230
|
```
|
|
149
231
|
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
Cardano wallet configuration:
|
|
232
|
+
### `WalletSettingsSchema`
|
|
153
233
|
|
|
154
234
|
```typescript
|
|
155
235
|
Type.Union([
|
|
156
236
|
Type.Object({
|
|
157
237
|
type: Type.Literal("hot"),
|
|
158
|
-
privateKey: Type.String({ minLength: 1, title: "Hot Wallet Private Key" })
|
|
238
|
+
privateKey: Type.String({ minLength: 1, title: "Hot Wallet Private Key", sensitive: true }),
|
|
159
239
|
}),
|
|
160
240
|
Type.Object({
|
|
161
241
|
type: Type.Literal("cold"),
|
|
162
|
-
address: Type.String({ minLength: 1, title: "Cold Wallet Address" })
|
|
163
|
-
})
|
|
242
|
+
address: Type.String({ minLength: 1, title: "Cold Wallet Address" }),
|
|
243
|
+
}),
|
|
164
244
|
])
|
|
165
245
|
```
|
|
166
246
|
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
Cardano multisig script schema with support for:
|
|
170
|
-
- Signature verification
|
|
171
|
-
- AllOf (all signatures required)
|
|
172
|
-
- AnyOf (any signature works)
|
|
173
|
-
- AtLeast (m-of-n threshold)
|
|
174
|
-
- Before/After (time-based conditions)
|
|
175
|
-
- Script hash references
|
|
176
|
-
|
|
177
|
-
## Advanced Usage
|
|
178
|
-
|
|
179
|
-
### Creating Nested Menus
|
|
180
|
-
|
|
181
|
-
```typescript
|
|
182
|
-
const menu = {
|
|
183
|
-
title: "Main Menu",
|
|
184
|
-
items: [
|
|
185
|
-
{
|
|
186
|
-
title: "User Management",
|
|
187
|
-
items: [
|
|
188
|
-
{
|
|
189
|
-
title: "Add User",
|
|
190
|
-
action: async (sprinkle) => {
|
|
191
|
-
// Add user logic
|
|
192
|
-
}
|
|
193
|
-
},
|
|
194
|
-
{
|
|
195
|
-
title: "Remove User",
|
|
196
|
-
action: async (sprinkle) => {
|
|
197
|
-
// Remove user logic
|
|
198
|
-
}
|
|
199
|
-
}
|
|
200
|
-
]
|
|
201
|
-
}
|
|
202
|
-
]
|
|
203
|
-
};
|
|
204
|
-
```
|
|
205
|
-
|
|
206
|
-
### Modifying Settings from Actions
|
|
207
|
-
|
|
208
|
-
```typescript
|
|
209
|
-
{
|
|
210
|
-
title: "Change Username",
|
|
211
|
-
action: async (sprinkle) => {
|
|
212
|
-
const newSettings = await sprinkle.EditStruct(
|
|
213
|
-
Type.Object({ username: Type.String() }),
|
|
214
|
-
{ username: sprinkle.settings.username }
|
|
215
|
-
);
|
|
216
|
-
return new Sprinkle(sprinkle.type, sprinkle.storagePath);
|
|
217
|
-
}
|
|
218
|
-
}
|
|
219
|
-
```
|
|
220
|
-
|
|
221
|
-
### Working with Cardano Transactions
|
|
247
|
+
## Examples
|
|
222
248
|
|
|
223
|
-
|
|
224
|
-
const blaze = await Sprinkle.GetBlaze(
|
|
225
|
-
"preprod",
|
|
226
|
-
providerSettings,
|
|
227
|
-
walletSettings
|
|
228
|
-
);
|
|
229
|
-
|
|
230
|
-
// Build your transaction
|
|
231
|
-
const tx = await blaze
|
|
232
|
-
.newTransaction()
|
|
233
|
-
.payLovelace(recipientAddress, 5_000_000n)
|
|
234
|
-
.complete();
|
|
235
|
-
|
|
236
|
-
// Show transaction dialog
|
|
237
|
-
await app.TxDialog(blaze, tx);
|
|
238
|
-
```
|
|
239
|
-
|
|
240
|
-
## Settings Persistence
|
|
241
|
-
|
|
242
|
-
Settings are automatically saved to `{storagePath}/settings.json`. The file format includes:
|
|
243
|
-
|
|
244
|
-
```json
|
|
245
|
-
{
|
|
246
|
-
"settings": {
|
|
247
|
-
"username": "alice",
|
|
248
|
-
"count": "42n"
|
|
249
|
-
},
|
|
250
|
-
"defaults": {
|
|
251
|
-
"string": "last_entered_value"
|
|
252
|
-
}
|
|
253
|
-
}
|
|
254
|
-
```
|
|
249
|
+
See [`examples/`](./examples/) for runnable examples:
|
|
255
250
|
|
|
256
|
-
|
|
251
|
+
- **[`demo-app/`](./examples/demo-app/)** — Full-featured testing harness exercising all built-in actions across TUI, CLI, and MCP modes
|
|
252
|
+
- **[`action-example.ts`](./examples/action-example.ts)** — Multi-mode example with a custom action
|
|
253
|
+
- **[`action-in-menu.ts`](./examples/action-in-menu.ts)** — TUI menu integration patterns
|
|
257
254
|
|
|
258
255
|
## License
|
|
259
256
|
|
|
@@ -49,13 +49,13 @@ async function makeSprinkle(storagePath, profileId = "default", settings = {
|
|
|
49
49
|
return sprinkle;
|
|
50
50
|
}
|
|
51
51
|
(0, _bunTest.describe)("getBuiltinActions", () => {
|
|
52
|
-
(0, _bunTest.test)("returns an array of
|
|
52
|
+
(0, _bunTest.test)("returns an array of 21 actions", () => {
|
|
53
53
|
const actions = (0, _index.getBuiltinActions)();
|
|
54
|
-
(0, _bunTest.expect)(actions).toHaveLength(
|
|
54
|
+
(0, _bunTest.expect)(actions).toHaveLength(21);
|
|
55
55
|
});
|
|
56
56
|
(0, _bunTest.test)("all actions have a category", () => {
|
|
57
57
|
const actions = (0, _index.getBuiltinActions)();
|
|
58
|
-
const validCategories = ["sprinkles", "wallet", "transaction"];
|
|
58
|
+
const validCategories = ["sprinkles", "wallet", "transaction", "utility", "addressbook"];
|
|
59
59
|
for (const action of actions) {
|
|
60
60
|
(0, _bunTest.expect)(validCategories).toContain(action.category);
|
|
61
61
|
}
|
|
@@ -83,7 +83,7 @@ async function makeSprinkle(storagePath, profileId = "default", settings = {
|
|
|
83
83
|
for (const action of actions) {
|
|
84
84
|
sprinkle.registerAction(action);
|
|
85
85
|
}
|
|
86
|
-
(0, _bunTest.expect)(sprinkle.listActions()).toHaveLength(
|
|
86
|
+
(0, _bunTest.expect)(sprinkle.listActions()).toHaveLength(21);
|
|
87
87
|
});
|
|
88
88
|
});
|
|
89
89
|
|