@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.
- package/dist/cjs/Sprinkle/__tests__/action-integration.test.js +590 -0
- package/dist/cjs/Sprinkle/__tests__/action-integration.test.js.map +1 -0
- package/dist/cjs/Sprinkle/__tests__/action-registry.test.js +193 -0
- package/dist/cjs/Sprinkle/__tests__/action-registry.test.js.map +1 -0
- package/dist/cjs/Sprinkle/__tests__/action-runner.test.js +304 -0
- package/dist/cjs/Sprinkle/__tests__/action-runner.test.js.map +1 -0
- package/dist/cjs/Sprinkle/__tests__/builtin-actions.test.js +1110 -0
- package/dist/cjs/Sprinkle/__tests__/builtin-actions.test.js.map +1 -0
- package/dist/cjs/Sprinkle/__tests__/cli-adapter.test.js +722 -0
- package/dist/cjs/Sprinkle/__tests__/cli-adapter.test.js.map +1 -0
- package/dist/cjs/Sprinkle/__tests__/fill-in-struct.test.js +138 -0
- package/dist/cjs/Sprinkle/__tests__/fill-in-struct.test.js.map +1 -1
- package/dist/cjs/Sprinkle/__tests__/mcp-adapter.test.js +713 -0
- package/dist/cjs/Sprinkle/__tests__/mcp-adapter.test.js.map +1 -0
- package/dist/cjs/Sprinkle/__tests__/tui-helpers.test.js +334 -0
- package/dist/cjs/Sprinkle/__tests__/tui-helpers.test.js.map +1 -0
- package/dist/cjs/Sprinkle/__tests__/wallet-transaction-actions.test.js +749 -0
- package/dist/cjs/Sprinkle/__tests__/wallet-transaction-actions.test.js.map +1 -0
- package/dist/cjs/Sprinkle/actions/builtin/blaze-helper.js +61 -0
- package/dist/cjs/Sprinkle/actions/builtin/blaze-helper.js.map +1 -0
- package/dist/cjs/Sprinkle/actions/builtin/index.js +117 -0
- package/dist/cjs/Sprinkle/actions/builtin/index.js.map +1 -0
- package/dist/cjs/Sprinkle/actions/builtin/profile-actions.js +202 -0
- package/dist/cjs/Sprinkle/actions/builtin/profile-actions.js.map +1 -0
- package/dist/cjs/Sprinkle/actions/builtin/settings-actions.js +87 -0
- package/dist/cjs/Sprinkle/actions/builtin/settings-actions.js.map +1 -0
- package/dist/cjs/Sprinkle/actions/builtin/transaction-actions.js +345 -0
- package/dist/cjs/Sprinkle/actions/builtin/transaction-actions.js.map +1 -0
- package/dist/cjs/Sprinkle/actions/builtin/wallet-actions.js +212 -0
- package/dist/cjs/Sprinkle/actions/builtin/wallet-actions.js.map +1 -0
- package/dist/cjs/Sprinkle/actions/cli-adapter.js +372 -0
- package/dist/cjs/Sprinkle/actions/cli-adapter.js.map +1 -0
- package/dist/cjs/Sprinkle/actions/index.js +127 -0
- package/dist/cjs/Sprinkle/actions/index.js.map +1 -0
- package/dist/cjs/Sprinkle/actions/mcp-adapter.js +415 -0
- package/dist/cjs/Sprinkle/actions/mcp-adapter.js.map +1 -0
- package/dist/cjs/Sprinkle/actions/registry.js +92 -0
- package/dist/cjs/Sprinkle/actions/registry.js.map +1 -0
- package/dist/cjs/Sprinkle/actions/runner.js +190 -0
- package/dist/cjs/Sprinkle/actions/runner.js.map +1 -0
- package/dist/cjs/Sprinkle/actions/tui-helpers.js +96 -0
- package/dist/cjs/Sprinkle/actions/tui-helpers.js.map +1 -0
- package/dist/cjs/Sprinkle/actions/types.js +68 -0
- package/dist/cjs/Sprinkle/actions/types.js.map +1 -0
- package/dist/cjs/Sprinkle/index.js +451 -4
- package/dist/cjs/Sprinkle/index.js.map +1 -1
- package/dist/cjs/Sprinkle/prompts.js +12 -7
- package/dist/cjs/Sprinkle/prompts.js.map +1 -1
- package/dist/cjs/Sprinkle/type-guards.js +7 -1
- package/dist/cjs/Sprinkle/type-guards.js.map +1 -1
- package/dist/esm/Sprinkle/__tests__/action-integration.test.js +588 -0
- package/dist/esm/Sprinkle/__tests__/action-integration.test.js.map +1 -0
- package/dist/esm/Sprinkle/__tests__/action-registry.test.js +192 -0
- package/dist/esm/Sprinkle/__tests__/action-registry.test.js.map +1 -0
- package/dist/esm/Sprinkle/__tests__/action-runner.test.js +302 -0
- package/dist/esm/Sprinkle/__tests__/action-runner.test.js.map +1 -0
- package/dist/esm/Sprinkle/__tests__/builtin-actions.test.js +1107 -0
- package/dist/esm/Sprinkle/__tests__/builtin-actions.test.js.map +1 -0
- package/dist/esm/Sprinkle/__tests__/cli-adapter.test.js +720 -0
- package/dist/esm/Sprinkle/__tests__/cli-adapter.test.js.map +1 -0
- package/dist/esm/Sprinkle/__tests__/fill-in-struct.test.js +138 -0
- package/dist/esm/Sprinkle/__tests__/fill-in-struct.test.js.map +1 -1
- package/dist/esm/Sprinkle/__tests__/mcp-adapter.test.js +712 -0
- package/dist/esm/Sprinkle/__tests__/mcp-adapter.test.js.map +1 -0
- package/dist/esm/Sprinkle/__tests__/tui-helpers.test.js +332 -0
- package/dist/esm/Sprinkle/__tests__/tui-helpers.test.js.map +1 -0
- package/dist/esm/Sprinkle/__tests__/wallet-transaction-actions.test.js +747 -0
- package/dist/esm/Sprinkle/__tests__/wallet-transaction-actions.test.js.map +1 -0
- package/dist/esm/Sprinkle/actions/builtin/blaze-helper.js +55 -0
- package/dist/esm/Sprinkle/actions/builtin/blaze-helper.js.map +1 -0
- package/dist/esm/Sprinkle/actions/builtin/index.js +32 -0
- package/dist/esm/Sprinkle/actions/builtin/index.js.map +1 -0
- package/dist/esm/Sprinkle/actions/builtin/profile-actions.js +197 -0
- package/dist/esm/Sprinkle/actions/builtin/profile-actions.js.map +1 -0
- package/dist/esm/Sprinkle/actions/builtin/settings-actions.js +81 -0
- package/dist/esm/Sprinkle/actions/builtin/settings-actions.js.map +1 -0
- package/dist/esm/Sprinkle/actions/builtin/transaction-actions.js +340 -0
- package/dist/esm/Sprinkle/actions/builtin/transaction-actions.js.map +1 -0
- package/dist/esm/Sprinkle/actions/builtin/wallet-actions.js +207 -0
- package/dist/esm/Sprinkle/actions/builtin/wallet-actions.js.map +1 -0
- package/dist/esm/Sprinkle/actions/cli-adapter.js +361 -0
- package/dist/esm/Sprinkle/actions/cli-adapter.js.map +1 -0
- package/dist/esm/Sprinkle/actions/index.js +12 -0
- package/dist/esm/Sprinkle/actions/index.js.map +1 -0
- package/dist/esm/Sprinkle/actions/mcp-adapter.js +407 -0
- package/dist/esm/Sprinkle/actions/mcp-adapter.js.map +1 -0
- package/dist/esm/Sprinkle/actions/registry.js +85 -0
- package/dist/esm/Sprinkle/actions/registry.js.map +1 -0
- package/dist/esm/Sprinkle/actions/runner.js +182 -0
- package/dist/esm/Sprinkle/actions/runner.js.map +1 -0
- package/dist/esm/Sprinkle/actions/tui-helpers.js +91 -0
- package/dist/esm/Sprinkle/actions/tui-helpers.js.map +1 -0
- package/dist/esm/Sprinkle/actions/types.js +61 -0
- package/dist/esm/Sprinkle/actions/types.js.map +1 -0
- package/dist/esm/Sprinkle/index.js +299 -4
- package/dist/esm/Sprinkle/index.js.map +1 -1
- package/dist/esm/Sprinkle/prompts.js +12 -7
- package/dist/esm/Sprinkle/prompts.js.map +1 -1
- package/dist/esm/Sprinkle/type-guards.js +3 -0
- package/dist/esm/Sprinkle/type-guards.js.map +1 -1
- package/dist/types/Sprinkle/actions/builtin/blaze-helper.d.ts +39 -0
- package/dist/types/Sprinkle/actions/builtin/blaze-helper.d.ts.map +1 -0
- package/dist/types/Sprinkle/actions/builtin/index.d.ts +26 -0
- package/dist/types/Sprinkle/actions/builtin/index.d.ts.map +1 -0
- package/dist/types/Sprinkle/actions/builtin/profile-actions.d.ts +55 -0
- package/dist/types/Sprinkle/actions/builtin/profile-actions.d.ts.map +1 -0
- package/dist/types/Sprinkle/actions/builtin/settings-actions.d.ts +32 -0
- package/dist/types/Sprinkle/actions/builtin/settings-actions.d.ts.map +1 -0
- package/dist/types/Sprinkle/actions/builtin/transaction-actions.d.ts +70 -0
- package/dist/types/Sprinkle/actions/builtin/transaction-actions.d.ts.map +1 -0
- package/dist/types/Sprinkle/actions/builtin/wallet-actions.d.ts +50 -0
- package/dist/types/Sprinkle/actions/builtin/wallet-actions.d.ts.map +1 -0
- package/dist/types/Sprinkle/actions/cli-adapter.d.ts +104 -0
- package/dist/types/Sprinkle/actions/cli-adapter.d.ts.map +1 -0
- package/dist/types/Sprinkle/actions/index.d.ts +12 -0
- package/dist/types/Sprinkle/actions/index.d.ts.map +1 -0
- package/dist/types/Sprinkle/actions/mcp-adapter.d.ts +92 -0
- package/dist/types/Sprinkle/actions/mcp-adapter.d.ts.map +1 -0
- package/dist/types/Sprinkle/actions/registry.d.ts +42 -0
- package/dist/types/Sprinkle/actions/registry.d.ts.map +1 -0
- package/dist/types/Sprinkle/actions/runner.d.ts +45 -0
- package/dist/types/Sprinkle/actions/runner.d.ts.map +1 -0
- package/dist/types/Sprinkle/actions/tui-helpers.d.ts +53 -0
- package/dist/types/Sprinkle/actions/tui-helpers.d.ts.map +1 -0
- package/dist/types/Sprinkle/actions/types.d.ts +76 -0
- package/dist/types/Sprinkle/actions/types.d.ts.map +1 -0
- package/dist/types/Sprinkle/index.d.ts +81 -1
- package/dist/types/Sprinkle/index.d.ts.map +1 -1
- package/dist/types/Sprinkle/prompts.d.ts.map +1 -1
- package/dist/types/Sprinkle/type-guards.d.ts +4 -1
- package/dist/types/Sprinkle/type-guards.d.ts.map +1 -1
- package/dist/types/tsconfig.build.tsbuildinfo +1 -1
- package/package.json +9 -2
- package/src/Sprinkle/__tests__/action-integration.test.ts +558 -0
- package/src/Sprinkle/__tests__/action-registry.test.ts +187 -0
- package/src/Sprinkle/__tests__/action-runner.test.ts +324 -0
- package/src/Sprinkle/__tests__/builtin-actions.test.ts +1022 -0
- package/src/Sprinkle/__tests__/cli-adapter.test.ts +715 -0
- package/src/Sprinkle/__tests__/fill-in-struct.test.ts +144 -0
- package/src/Sprinkle/__tests__/mcp-adapter.test.ts +718 -0
- package/src/Sprinkle/__tests__/tui-helpers.test.ts +325 -0
- package/src/Sprinkle/__tests__/wallet-transaction-actions.test.ts +695 -0
- package/src/Sprinkle/actions/builtin/blaze-helper.ts +89 -0
- package/src/Sprinkle/actions/builtin/index.ts +86 -0
- package/src/Sprinkle/actions/builtin/profile-actions.ts +229 -0
- package/src/Sprinkle/actions/builtin/settings-actions.ts +99 -0
- package/src/Sprinkle/actions/builtin/transaction-actions.ts +381 -0
- package/src/Sprinkle/actions/builtin/wallet-actions.ts +233 -0
- package/src/Sprinkle/actions/cli-adapter.ts +430 -0
- package/src/Sprinkle/actions/index.ts +32 -0
- package/src/Sprinkle/actions/mcp-adapter.ts +463 -0
- package/src/Sprinkle/actions/registry.ts +97 -0
- package/src/Sprinkle/actions/runner.ts +200 -0
- package/src/Sprinkle/actions/tui-helpers.ts +114 -0
- package/src/Sprinkle/actions/types.ts +91 -0
- package/src/Sprinkle/index.ts +395 -3
- package/src/Sprinkle/prompts.ts +118 -72
- package/src/Sprinkle/type-guards.ts +9 -0
|
@@ -0,0 +1,89 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Shared helper utilities for wallet and transaction actions.
|
|
3
|
+
* Provides Blaze instance creation from action context settings.
|
|
4
|
+
*/
|
|
5
|
+
|
|
6
|
+
import type { TSchema } from "@sinclair/typebox";
|
|
7
|
+
import { Blaze, HotWallet } from "@blaze-cardano/sdk";
|
|
8
|
+
import type { Provider } from "@blaze-cardano/query";
|
|
9
|
+
import type { Wallet } from "@blaze-cardano/sdk";
|
|
10
|
+
import { GetBlaze } from "../../wallet.js";
|
|
11
|
+
import { ActionError } from "../types.js";
|
|
12
|
+
import type { IActionContext } from "../types.js";
|
|
13
|
+
import type {
|
|
14
|
+
NetworkSchema,
|
|
15
|
+
ProviderSettingsSchema,
|
|
16
|
+
WalletSettingsSchema,
|
|
17
|
+
} from "../../schemas.js";
|
|
18
|
+
import type { TExact } from "../../types.js";
|
|
19
|
+
|
|
20
|
+
/** Settings shape expected on context.settings for wallet access */
|
|
21
|
+
export interface IWalletSettings {
|
|
22
|
+
network?: TExact<typeof NetworkSchema>;
|
|
23
|
+
provider?: TExact<typeof ProviderSettingsSchema>;
|
|
24
|
+
wallet?: TExact<typeof WalletSettingsSchema>;
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
/** Optional overrides for Blaze initialization, in case field names differ */
|
|
28
|
+
export interface IBlazeOverrides {
|
|
29
|
+
network?: TExact<typeof NetworkSchema>;
|
|
30
|
+
provider?: TExact<typeof ProviderSettingsSchema>;
|
|
31
|
+
wallet?: TExact<typeof WalletSettingsSchema>;
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
/**
|
|
35
|
+
* Creates a Blaze instance from action context settings.
|
|
36
|
+
*
|
|
37
|
+
* Falls back to `context.settings.network`, `context.settings.provider`,
|
|
38
|
+
* and `context.settings.wallet` when overrides are not provided.
|
|
39
|
+
*
|
|
40
|
+
* @throws `ActionError("WALLET_NOT_CONFIGURED")` if required settings are missing
|
|
41
|
+
* @throws `ActionError("BLAZE_INIT_ERROR")` if Blaze fails to initialize
|
|
42
|
+
*/
|
|
43
|
+
export async function getBlazeFromContext<S extends TSchema>(
|
|
44
|
+
context: IActionContext<S>,
|
|
45
|
+
overrides?: IBlazeOverrides,
|
|
46
|
+
): Promise<Blaze<Provider, Wallet>> {
|
|
47
|
+
const settings = context.settings as unknown as IWalletSettings;
|
|
48
|
+
|
|
49
|
+
const network = overrides?.network ?? settings.network;
|
|
50
|
+
const provider = overrides?.provider ?? settings.provider;
|
|
51
|
+
const wallet = overrides?.wallet ?? settings.wallet;
|
|
52
|
+
|
|
53
|
+
// Validate required fields and collect missing ones for a helpful error message
|
|
54
|
+
const missing: string[] = [];
|
|
55
|
+
if (!network) missing.push("network");
|
|
56
|
+
if (!provider) missing.push("provider");
|
|
57
|
+
if (!wallet) missing.push("wallet");
|
|
58
|
+
|
|
59
|
+
if (missing.length > 0) {
|
|
60
|
+
throw new ActionError(
|
|
61
|
+
`Wallet is not configured. Missing settings: ${missing.join(", ")}. ` +
|
|
62
|
+
`Set these fields in your profile settings before using wallet actions.`,
|
|
63
|
+
"WALLET_NOT_CONFIGURED",
|
|
64
|
+
{ missingFields: missing },
|
|
65
|
+
);
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
try {
|
|
69
|
+
return await GetBlaze(
|
|
70
|
+
network as TExact<typeof NetworkSchema>,
|
|
71
|
+
provider as TExact<typeof ProviderSettingsSchema>,
|
|
72
|
+
wallet as TExact<typeof WalletSettingsSchema>,
|
|
73
|
+
);
|
|
74
|
+
} catch (err) {
|
|
75
|
+
throw new ActionError(
|
|
76
|
+
`Failed to initialize Blaze wallet: ${err instanceof Error ? err.message : String(err)}`,
|
|
77
|
+
"BLAZE_INIT_ERROR",
|
|
78
|
+
{ error: err instanceof Error ? err.message : String(err) },
|
|
79
|
+
);
|
|
80
|
+
}
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
/**
|
|
84
|
+
* Checks whether the wallet in a Blaze instance is a hot wallet.
|
|
85
|
+
* Cold wallets cannot sign transactions.
|
|
86
|
+
*/
|
|
87
|
+
export function isHotWallet(blaze: Blaze<Provider, Wallet>): boolean {
|
|
88
|
+
return blaze.wallet instanceof HotWallet;
|
|
89
|
+
}
|
|
@@ -0,0 +1,86 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Barrel export for built-in Sprinkle actions.
|
|
3
|
+
*
|
|
4
|
+
* Provides a `getBuiltinActions()` factory that returns all 14 built-in actions
|
|
5
|
+
* ready for registration on an ActionRegistry.
|
|
6
|
+
*/
|
|
7
|
+
|
|
8
|
+
import type { TSchema } from "@sinclair/typebox";
|
|
9
|
+
import type { AnyAction } from "../types.js";
|
|
10
|
+
|
|
11
|
+
export {
|
|
12
|
+
listProfiles,
|
|
13
|
+
getProfile,
|
|
14
|
+
setProfile,
|
|
15
|
+
createProfile,
|
|
16
|
+
deleteProfile,
|
|
17
|
+
} from "./profile-actions.js";
|
|
18
|
+
|
|
19
|
+
export { getSettings, updateSettings } from "./settings-actions.js";
|
|
20
|
+
|
|
21
|
+
export {
|
|
22
|
+
getWalletAddress,
|
|
23
|
+
getWalletBalance,
|
|
24
|
+
getWalletUtxos,
|
|
25
|
+
} from "./wallet-actions.js";
|
|
26
|
+
|
|
27
|
+
export {
|
|
28
|
+
signTransaction,
|
|
29
|
+
submitTransaction,
|
|
30
|
+
signAndSubmit,
|
|
31
|
+
decodeTransaction,
|
|
32
|
+
} from "./transaction-actions.js";
|
|
33
|
+
|
|
34
|
+
import {
|
|
35
|
+
listProfiles,
|
|
36
|
+
getProfile,
|
|
37
|
+
setProfile,
|
|
38
|
+
createProfile,
|
|
39
|
+
deleteProfile,
|
|
40
|
+
} from "./profile-actions.js";
|
|
41
|
+
|
|
42
|
+
import { getSettings, updateSettings } from "./settings-actions.js";
|
|
43
|
+
|
|
44
|
+
import {
|
|
45
|
+
getWalletAddress,
|
|
46
|
+
getWalletBalance,
|
|
47
|
+
getWalletUtxos,
|
|
48
|
+
} from "./wallet-actions.js";
|
|
49
|
+
|
|
50
|
+
import {
|
|
51
|
+
signTransaction,
|
|
52
|
+
submitTransaction,
|
|
53
|
+
signAndSubmit,
|
|
54
|
+
decodeTransaction,
|
|
55
|
+
} from "./transaction-actions.js";
|
|
56
|
+
|
|
57
|
+
/**
|
|
58
|
+
* Returns an array of all 14 built-in Sprinkle actions.
|
|
59
|
+
* Register them on your ActionRegistry or pass them to `Sprinkle.run()`.
|
|
60
|
+
*
|
|
61
|
+
* @example
|
|
62
|
+
* ```ts
|
|
63
|
+
* const sprinkle = new Sprinkle(MySchema, storagePath);
|
|
64
|
+
* for (const action of getBuiltinActions()) {
|
|
65
|
+
* sprinkle.registerAction(action);
|
|
66
|
+
* }
|
|
67
|
+
* ```
|
|
68
|
+
*/
|
|
69
|
+
export function getBuiltinActions<S extends TSchema>(): AnyAction<S>[] {
|
|
70
|
+
return [
|
|
71
|
+
listProfiles,
|
|
72
|
+
getProfile,
|
|
73
|
+
setProfile,
|
|
74
|
+
createProfile,
|
|
75
|
+
deleteProfile,
|
|
76
|
+
getSettings,
|
|
77
|
+
updateSettings,
|
|
78
|
+
getWalletAddress,
|
|
79
|
+
getWalletBalance,
|
|
80
|
+
getWalletUtxos,
|
|
81
|
+
signTransaction,
|
|
82
|
+
submitTransaction,
|
|
83
|
+
signAndSubmit,
|
|
84
|
+
decodeTransaction,
|
|
85
|
+
] as unknown as AnyAction<S>[];
|
|
86
|
+
}
|
|
@@ -0,0 +1,229 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Built-in profile management actions for the Sprinkle action system.
|
|
3
|
+
* These actions expose profile CRUD operations as non-interactive actions
|
|
4
|
+
* available in CLI and MCP modes.
|
|
5
|
+
*
|
|
6
|
+
* All actions use category "sprinkles".
|
|
7
|
+
*/
|
|
8
|
+
|
|
9
|
+
import { Type } from "@sinclair/typebox";
|
|
10
|
+
import type { TSchema } from "@sinclair/typebox";
|
|
11
|
+
import { ActionError } from "../types.js";
|
|
12
|
+
import type { IAction } from "../types.js";
|
|
13
|
+
|
|
14
|
+
/** Shape of a profile entry as returned by profile actions */
|
|
15
|
+
const ProfileEntrySchema = Type.Object({
|
|
16
|
+
id: Type.String(),
|
|
17
|
+
name: Type.String(),
|
|
18
|
+
description: Type.Optional(Type.String()),
|
|
19
|
+
createdAt: Type.String(),
|
|
20
|
+
updatedAt: Type.String(),
|
|
21
|
+
});
|
|
22
|
+
|
|
23
|
+
/**
|
|
24
|
+
* `list-profiles` -- Returns all profiles and the active profile ID.
|
|
25
|
+
*/
|
|
26
|
+
export const listProfiles: IAction<
|
|
27
|
+
Record<string, never>,
|
|
28
|
+
{ profiles: unknown[]; activeProfileId: string | undefined },
|
|
29
|
+
TSchema
|
|
30
|
+
> = {
|
|
31
|
+
name: "list-profiles",
|
|
32
|
+
description: "List all profiles and indicate which one is currently active.",
|
|
33
|
+
category: "sprinkles",
|
|
34
|
+
inputSchema: Type.Object({}),
|
|
35
|
+
outputSchema: Type.Object({
|
|
36
|
+
profiles: Type.Array(ProfileEntrySchema),
|
|
37
|
+
activeProfileId: Type.Optional(Type.String()),
|
|
38
|
+
}),
|
|
39
|
+
execute: async (_input, context) => {
|
|
40
|
+
const entries = context.sprinkle.scanProfiles();
|
|
41
|
+
const profiles = entries.map((e) => ({
|
|
42
|
+
id: e.id,
|
|
43
|
+
name: e.meta.name,
|
|
44
|
+
description: e.meta.description,
|
|
45
|
+
createdAt: e.meta.createdAt,
|
|
46
|
+
updatedAt: e.meta.updatedAt,
|
|
47
|
+
}));
|
|
48
|
+
return {
|
|
49
|
+
profiles,
|
|
50
|
+
activeProfileId: context.sprinkle.currentProfile?.id,
|
|
51
|
+
};
|
|
52
|
+
},
|
|
53
|
+
};
|
|
54
|
+
|
|
55
|
+
/**
|
|
56
|
+
* `get-profile` -- Returns metadata and settings for a specific profile.
|
|
57
|
+
* Settings are masked by default; pass `includeSensitive: true` to get raw values.
|
|
58
|
+
*/
|
|
59
|
+
export const getProfile: IAction<
|
|
60
|
+
{ id: string; includeSensitive?: boolean },
|
|
61
|
+
unknown,
|
|
62
|
+
TSchema
|
|
63
|
+
> = {
|
|
64
|
+
name: "get-profile",
|
|
65
|
+
description:
|
|
66
|
+
"Get metadata and settings for a profile. Sensitive fields are masked by default.",
|
|
67
|
+
category: "sprinkles",
|
|
68
|
+
inputSchema: Type.Object({
|
|
69
|
+
id: Type.String(),
|
|
70
|
+
includeSensitive: Type.Optional(Type.Boolean({ default: false })),
|
|
71
|
+
}),
|
|
72
|
+
outputSchema: Type.Object({
|
|
73
|
+
id: Type.String(),
|
|
74
|
+
name: Type.String(),
|
|
75
|
+
description: Type.Optional(Type.String()),
|
|
76
|
+
createdAt: Type.String(),
|
|
77
|
+
updatedAt: Type.String(),
|
|
78
|
+
settings: Type.Any(),
|
|
79
|
+
}),
|
|
80
|
+
execute: async (input, context) => {
|
|
81
|
+
// Validate ID to prevent path traversal (defense in depth)
|
|
82
|
+
if (input.id.includes("/") || input.id.includes("\\") || input.id.includes("..")) {
|
|
83
|
+
throw new ActionError(
|
|
84
|
+
`Invalid profile ID "${input.id}".`,
|
|
85
|
+
"INVALID_PROFILE_ID",
|
|
86
|
+
{ id: input.id },
|
|
87
|
+
);
|
|
88
|
+
}
|
|
89
|
+
|
|
90
|
+
const profile = context.sprinkle.getProfileById(input.id);
|
|
91
|
+
if (!profile) {
|
|
92
|
+
throw new ActionError(
|
|
93
|
+
`Profile "${input.id}" not found.`,
|
|
94
|
+
"PROFILE_NOT_FOUND",
|
|
95
|
+
{ id: input.id },
|
|
96
|
+
);
|
|
97
|
+
}
|
|
98
|
+
|
|
99
|
+
// Read the profile file to get settings
|
|
100
|
+
const fs = await import("fs");
|
|
101
|
+
const path = await import("path");
|
|
102
|
+
const storagePath = context.sprinkle.storagePath;
|
|
103
|
+
|
|
104
|
+
const profilePath = path.join(storagePath, "profiles", `${input.id}.json`);
|
|
105
|
+
let settings: unknown = {};
|
|
106
|
+
try {
|
|
107
|
+
const content = fs.readFileSync(profilePath, "utf-8");
|
|
108
|
+
const parsed = JSON.parse(content);
|
|
109
|
+
settings = parsed.settings ?? {};
|
|
110
|
+
} catch (err) {
|
|
111
|
+
// Throw an error so the caller knows the profile file couldn't be read
|
|
112
|
+
throw new ActionError(
|
|
113
|
+
`Failed to read profile "${input.id}": ${err instanceof Error ? err.message : String(err)}`,
|
|
114
|
+
"PROFILE_READ_ERROR",
|
|
115
|
+
{ id: input.id, error: err instanceof Error ? err.message : String(err) },
|
|
116
|
+
);
|
|
117
|
+
}
|
|
118
|
+
|
|
119
|
+
// Mask sensitive fields unless includeSensitive is true
|
|
120
|
+
if (!input.includeSensitive) {
|
|
121
|
+
const { maskSensitiveFields } = await import("../../encryption.js");
|
|
122
|
+
settings = maskSensitiveFields(settings, context.sprinkle.type);
|
|
123
|
+
}
|
|
124
|
+
|
|
125
|
+
return {
|
|
126
|
+
id: profile.id,
|
|
127
|
+
name: profile.meta.name,
|
|
128
|
+
description: profile.meta.description,
|
|
129
|
+
createdAt: profile.meta.createdAt,
|
|
130
|
+
updatedAt: profile.meta.updatedAt,
|
|
131
|
+
settings,
|
|
132
|
+
};
|
|
133
|
+
},
|
|
134
|
+
};
|
|
135
|
+
|
|
136
|
+
/**
|
|
137
|
+
* `set-profile` -- Switch the active profile.
|
|
138
|
+
*/
|
|
139
|
+
export const setProfile: IAction<
|
|
140
|
+
{ id: string },
|
|
141
|
+
{ id: string; name: string },
|
|
142
|
+
TSchema
|
|
143
|
+
> = {
|
|
144
|
+
name: "set-profile",
|
|
145
|
+
description: "Switch the active profile.",
|
|
146
|
+
category: "sprinkles",
|
|
147
|
+
inputSchema: Type.Object({
|
|
148
|
+
id: Type.String(),
|
|
149
|
+
}),
|
|
150
|
+
outputSchema: Type.Object({
|
|
151
|
+
id: Type.String(),
|
|
152
|
+
name: Type.String(),
|
|
153
|
+
}),
|
|
154
|
+
execute: async (input, context) => {
|
|
155
|
+
const profile = context.sprinkle.getProfileById(input.id);
|
|
156
|
+
if (!profile) {
|
|
157
|
+
throw new ActionError(
|
|
158
|
+
`Profile "${input.id}" not found.`,
|
|
159
|
+
"PROFILE_NOT_FOUND",
|
|
160
|
+
{ id: input.id },
|
|
161
|
+
);
|
|
162
|
+
}
|
|
163
|
+
|
|
164
|
+
await context.sprinkle.loadProfile(input.id);
|
|
165
|
+
return {
|
|
166
|
+
id: input.id,
|
|
167
|
+
name: profile.meta.name,
|
|
168
|
+
};
|
|
169
|
+
},
|
|
170
|
+
};
|
|
171
|
+
|
|
172
|
+
/**
|
|
173
|
+
* `create-profile` -- Create a new profile without prompts.
|
|
174
|
+
*/
|
|
175
|
+
export const createProfile: IAction<
|
|
176
|
+
{ name: string; description?: string; settings?: unknown },
|
|
177
|
+
{ id: string; name: string },
|
|
178
|
+
TSchema
|
|
179
|
+
> = {
|
|
180
|
+
name: "create-profile",
|
|
181
|
+
description: "Create a new profile.",
|
|
182
|
+
category: "sprinkles",
|
|
183
|
+
inputSchema: Type.Object({
|
|
184
|
+
name: Type.String(),
|
|
185
|
+
description: Type.Optional(Type.String()),
|
|
186
|
+
settings: Type.Optional(Type.Any()),
|
|
187
|
+
}),
|
|
188
|
+
outputSchema: Type.Object({
|
|
189
|
+
id: Type.String(),
|
|
190
|
+
name: Type.String(),
|
|
191
|
+
}),
|
|
192
|
+
execute: async (input, context) => {
|
|
193
|
+
const entry = await context.sprinkle.createProfileNonInteractive(
|
|
194
|
+
input.name,
|
|
195
|
+
input.description,
|
|
196
|
+
input.settings as never,
|
|
197
|
+
);
|
|
198
|
+
return {
|
|
199
|
+
id: entry.id,
|
|
200
|
+
name: entry.meta.name,
|
|
201
|
+
};
|
|
202
|
+
},
|
|
203
|
+
};
|
|
204
|
+
|
|
205
|
+
/**
|
|
206
|
+
* `delete-profile` -- Delete a profile by ID.
|
|
207
|
+
* Cannot delete the only profile or the currently active profile.
|
|
208
|
+
*/
|
|
209
|
+
export const deleteProfile: IAction<
|
|
210
|
+
{ id: string },
|
|
211
|
+
{ deleted: boolean; id: string },
|
|
212
|
+
TSchema
|
|
213
|
+
> = {
|
|
214
|
+
name: "delete-profile",
|
|
215
|
+
description:
|
|
216
|
+
"Delete a profile. Cannot delete the only profile or the active profile.",
|
|
217
|
+
category: "sprinkles",
|
|
218
|
+
inputSchema: Type.Object({
|
|
219
|
+
id: Type.String(),
|
|
220
|
+
}),
|
|
221
|
+
outputSchema: Type.Object({
|
|
222
|
+
deleted: Type.Boolean(),
|
|
223
|
+
id: Type.String(),
|
|
224
|
+
}),
|
|
225
|
+
execute: async (input, context) => {
|
|
226
|
+
context.sprinkle.deleteProfileById(input.id);
|
|
227
|
+
return { deleted: true, id: input.id };
|
|
228
|
+
},
|
|
229
|
+
};
|
|
@@ -0,0 +1,99 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Built-in settings actions for the Sprinkle action system.
|
|
3
|
+
* These actions expose settings read and update operations as non-interactive
|
|
4
|
+
* actions available in CLI and MCP modes.
|
|
5
|
+
*
|
|
6
|
+
* All actions use category "sprinkles".
|
|
7
|
+
*/
|
|
8
|
+
|
|
9
|
+
import { Type } from "@sinclair/typebox";
|
|
10
|
+
import { Value } from "@sinclair/typebox/value";
|
|
11
|
+
import type { TSchema } from "@sinclair/typebox";
|
|
12
|
+
import { ActionError } from "../types.js";
|
|
13
|
+
import type { IAction } from "../types.js";
|
|
14
|
+
|
|
15
|
+
/**
|
|
16
|
+
* `get-settings` -- Returns the current profile settings.
|
|
17
|
+
* Sensitive fields are masked by default; pass `includeSensitive: true` for raw values.
|
|
18
|
+
*/
|
|
19
|
+
export const getSettings: IAction<
|
|
20
|
+
{ includeSensitive?: boolean },
|
|
21
|
+
{ settings: unknown; profileId: string; profileName: string },
|
|
22
|
+
TSchema
|
|
23
|
+
> = {
|
|
24
|
+
name: "get-settings",
|
|
25
|
+
description:
|
|
26
|
+
"Get the current profile settings. Sensitive fields are masked by default.",
|
|
27
|
+
category: "sprinkles",
|
|
28
|
+
inputSchema: Type.Object({
|
|
29
|
+
includeSensitive: Type.Optional(Type.Boolean({ default: false })),
|
|
30
|
+
}),
|
|
31
|
+
outputSchema: Type.Object({
|
|
32
|
+
settings: Type.Any(),
|
|
33
|
+
profileId: Type.String(),
|
|
34
|
+
profileName: Type.String(),
|
|
35
|
+
}),
|
|
36
|
+
execute: async (input, context) => {
|
|
37
|
+
const settings = input.includeSensitive
|
|
38
|
+
? context.sprinkle.settings
|
|
39
|
+
: context.sprinkle.getDisplaySettings();
|
|
40
|
+
|
|
41
|
+
return {
|
|
42
|
+
settings,
|
|
43
|
+
profileId: context.sprinkle.profileId,
|
|
44
|
+
profileName: context.sprinkle.profileMeta.name,
|
|
45
|
+
};
|
|
46
|
+
},
|
|
47
|
+
};
|
|
48
|
+
|
|
49
|
+
/**
|
|
50
|
+
* `update-settings` -- Shallow-merges settings onto the current profile and persists.
|
|
51
|
+
* Validates the merged result against the Sprinkle schema before saving.
|
|
52
|
+
* Returns masked settings.
|
|
53
|
+
*/
|
|
54
|
+
export const updateSettings: IAction<
|
|
55
|
+
{ settings: Record<string, unknown> },
|
|
56
|
+
{ settings: unknown; profileId: string },
|
|
57
|
+
TSchema
|
|
58
|
+
> = {
|
|
59
|
+
name: "update-settings",
|
|
60
|
+
description:
|
|
61
|
+
"Merge partial settings onto the current profile and save. Returns masked settings.",
|
|
62
|
+
category: "sprinkles",
|
|
63
|
+
inputSchema: Type.Object({
|
|
64
|
+
settings: Type.Record(Type.String(), Type.Any()),
|
|
65
|
+
}),
|
|
66
|
+
outputSchema: Type.Object({
|
|
67
|
+
settings: Type.Any(),
|
|
68
|
+
profileId: Type.String(),
|
|
69
|
+
}),
|
|
70
|
+
execute: async (input, context) => {
|
|
71
|
+
// Shallow merge the incoming settings onto the current settings
|
|
72
|
+
const merged = {
|
|
73
|
+
...(context.sprinkle.settings as Record<string, unknown>),
|
|
74
|
+
...input.settings,
|
|
75
|
+
};
|
|
76
|
+
|
|
77
|
+
// Validate the merged result against the Sprinkle schema
|
|
78
|
+
if (!Value.Check(context.sprinkle.type, merged)) {
|
|
79
|
+
const errors = [...Value.Errors(context.sprinkle.type, merged)];
|
|
80
|
+
const message = errors
|
|
81
|
+
.map((e) => `${e.path}: ${e.message}`)
|
|
82
|
+
.join("; ");
|
|
83
|
+
throw new ActionError(
|
|
84
|
+
`Settings validation failed: ${message}`,
|
|
85
|
+
"VALIDATION_ERROR",
|
|
86
|
+
{ errors },
|
|
87
|
+
);
|
|
88
|
+
}
|
|
89
|
+
|
|
90
|
+
// Apply and persist
|
|
91
|
+
context.sprinkle.settings = merged as typeof context.sprinkle.settings;
|
|
92
|
+
context.sprinkle.saveSettings();
|
|
93
|
+
|
|
94
|
+
return {
|
|
95
|
+
settings: context.sprinkle.getDisplaySettings(),
|
|
96
|
+
profileId: context.sprinkle.profileId,
|
|
97
|
+
};
|
|
98
|
+
},
|
|
99
|
+
};
|