@kaleidorg/mind 0.3.0 → 0.5.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 (132) hide show
  1. package/dist/funnel.d.ts +19 -0
  2. package/dist/funnel.d.ts.map +1 -1
  3. package/dist/funnel.js +48 -10
  4. package/dist/funnel.js.map +1 -1
  5. package/dist/index.d.ts +5 -2
  6. package/dist/index.d.ts.map +1 -1
  7. package/dist/index.js +10 -3
  8. package/dist/index.js.map +1 -1
  9. package/dist/kaleidoswap/contract.d.ts +3 -3
  10. package/dist/kaleidoswap/contract.d.ts.map +1 -1
  11. package/dist/kaleidoswap/contract.js +16 -4
  12. package/dist/kaleidoswap/contract.js.map +1 -1
  13. package/dist/knowledge/bitcoin-copilot.d.ts.map +1 -1
  14. package/dist/knowledge/bitcoin-copilot.js +102 -0
  15. package/dist/knowledge/bitcoin-copilot.js.map +1 -1
  16. package/dist/knowledge/btc-map.d.ts +14 -17
  17. package/dist/knowledge/btc-map.d.ts.map +1 -1
  18. package/dist/knowledge/btc-map.js +66 -266
  19. package/dist/knowledge/btc-map.js.map +1 -1
  20. package/dist/lsps1/contract.d.ts.map +1 -1
  21. package/dist/lsps1/contract.js +28 -10
  22. package/dist/lsps1/contract.js.map +1 -1
  23. package/dist/qvac/assistant.d.ts +73 -0
  24. package/dist/qvac/assistant.d.ts.map +1 -0
  25. package/dist/qvac/assistant.js +97 -0
  26. package/dist/qvac/assistant.js.map +1 -0
  27. package/dist/qvac/config.d.ts +64 -0
  28. package/dist/qvac/config.d.ts.map +1 -0
  29. package/dist/qvac/config.js +71 -0
  30. package/dist/qvac/config.js.map +1 -0
  31. package/dist/qvac/delegate.d.ts +48 -0
  32. package/dist/qvac/delegate.d.ts.map +1 -0
  33. package/dist/qvac/delegate.js +51 -0
  34. package/dist/qvac/delegate.js.map +1 -0
  35. package/dist/qvac/index.d.ts +19 -0
  36. package/dist/qvac/index.d.ts.map +1 -0
  37. package/dist/qvac/index.js +19 -0
  38. package/dist/qvac/index.js.map +1 -0
  39. package/dist/qvac/parse.d.ts +44 -0
  40. package/dist/qvac/parse.d.ts.map +1 -0
  41. package/dist/qvac/parse.js +28 -0
  42. package/dist/qvac/parse.js.map +1 -0
  43. package/dist/qvac/provider.d.ts +49 -0
  44. package/dist/qvac/provider.d.ts.map +1 -0
  45. package/dist/qvac/provider.js +68 -0
  46. package/dist/qvac/provider.js.map +1 -0
  47. package/dist/qvac/stream.d.ts +37 -0
  48. package/dist/qvac/stream.d.ts.map +1 -0
  49. package/dist/qvac/stream.js +29 -0
  50. package/dist/qvac/stream.js.map +1 -0
  51. package/dist/qvac/text.d.ts +19 -0
  52. package/dist/qvac/text.d.ts.map +1 -0
  53. package/dist/qvac/text.js +56 -0
  54. package/dist/qvac/text.js.map +1 -0
  55. package/dist/qvac/voice.d.ts +69 -0
  56. package/dist/qvac/voice.d.ts.map +1 -0
  57. package/dist/qvac/voice.js +51 -0
  58. package/dist/qvac/voice.js.map +1 -0
  59. package/dist/recipe/buy-asset-channel.d.ts +26 -0
  60. package/dist/recipe/buy-asset-channel.d.ts.map +1 -0
  61. package/dist/recipe/buy-asset-channel.js +112 -0
  62. package/dist/recipe/buy-asset-channel.js.map +1 -0
  63. package/dist/recipe/kaleidoswap-atomic.d.ts +26 -18
  64. package/dist/recipe/kaleidoswap-atomic.d.ts.map +1 -1
  65. package/dist/recipe/kaleidoswap-atomic.js +101 -63
  66. package/dist/recipe/kaleidoswap-atomic.js.map +1 -1
  67. package/dist/recipe/kaleidoswap-channel-order.d.ts +35 -0
  68. package/dist/recipe/kaleidoswap-channel-order.d.ts.map +1 -0
  69. package/dist/recipe/kaleidoswap-channel-order.js +493 -0
  70. package/dist/recipe/kaleidoswap-channel-order.js.map +1 -0
  71. package/dist/recipe/kaleidoswap-price.d.ts +21 -0
  72. package/dist/recipe/kaleidoswap-price.d.ts.map +1 -0
  73. package/dist/recipe/kaleidoswap-price.js +57 -0
  74. package/dist/recipe/kaleidoswap-price.js.map +1 -0
  75. package/dist/recipe/runner.d.ts +7 -1
  76. package/dist/recipe/runner.d.ts.map +1 -1
  77. package/dist/recipe/runner.js +115 -29
  78. package/dist/recipe/runner.js.map +1 -1
  79. package/dist/recipe/swap.d.ts +26 -1
  80. package/dist/recipe/swap.d.ts.map +1 -1
  81. package/dist/recipe/swap.js +108 -13
  82. package/dist/recipe/swap.js.map +1 -1
  83. package/dist/recipe/types.d.ts +25 -1
  84. package/dist/recipe/types.d.ts.map +1 -1
  85. package/dist/skills/registry.d.ts +33 -1
  86. package/dist/skills/registry.d.ts.map +1 -1
  87. package/dist/skills/registry.js +45 -1
  88. package/dist/skills/registry.js.map +1 -1
  89. package/package.json +15 -1
  90. package/skills/README.md +3 -0
  91. package/skills/kaleido-lsps/SKILL.md +101 -43
  92. package/skills/kaleido-trading/SKILL.md +81 -31
  93. package/skills/merchant-finder/SKILL.md +96 -66
  94. package/skills/rgb-lightning-node/SKILL.md +108 -0
  95. package/skills/wallet-assistant/SKILL.md +32 -21
  96. package/src/funnel.ts +66 -11
  97. package/src/index.ts +14 -2
  98. package/src/kaleidoswap/contract.test.ts +7 -2
  99. package/src/kaleidoswap/contract.ts +27 -5
  100. package/src/knowledge/bitcoin-copilot.ts +111 -0
  101. package/src/knowledge/btc-map.test.ts +53 -96
  102. package/src/knowledge/btc-map.ts +72 -287
  103. package/src/lsps1/contract.ts +32 -14
  104. package/src/qvac/assistant.test.ts +132 -0
  105. package/src/qvac/assistant.ts +146 -0
  106. package/src/qvac/config.test.ts +44 -0
  107. package/src/qvac/config.ts +76 -0
  108. package/src/qvac/delegate.test.ts +68 -0
  109. package/src/qvac/delegate.ts +71 -0
  110. package/src/qvac/index.ts +72 -0
  111. package/src/qvac/parse.test.ts +52 -0
  112. package/src/qvac/parse.ts +57 -0
  113. package/src/qvac/provider.test.ts +107 -0
  114. package/src/qvac/provider.ts +124 -0
  115. package/src/qvac/stream.test.ts +79 -0
  116. package/src/qvac/stream.ts +56 -0
  117. package/src/qvac/text.test.ts +70 -0
  118. package/src/qvac/text.ts +60 -0
  119. package/src/qvac/voice.test.ts +151 -0
  120. package/src/qvac/voice.ts +122 -0
  121. package/src/recipe/buy-asset-channel.test.ts +148 -0
  122. package/src/recipe/buy-asset-channel.ts +118 -0
  123. package/src/recipe/kaleidoswap-atomic.test.ts +134 -61
  124. package/src/recipe/kaleidoswap-atomic.ts +112 -66
  125. package/src/recipe/kaleidoswap-channel-order.test.ts +333 -0
  126. package/src/recipe/kaleidoswap-channel-order.ts +548 -0
  127. package/src/recipe/kaleidoswap-price.ts +68 -0
  128. package/src/recipe/recipe.test.ts +61 -5
  129. package/src/recipe/runner.ts +128 -31
  130. package/src/recipe/swap.ts +109 -13
  131. package/src/recipe/types.ts +25 -1
  132. package/src/skills/registry.ts +52 -1
@@ -0,0 +1,37 @@
1
+ /**
2
+ * Consume a QVAC `completion()` run: drain the event stream (forwarding visible
3
+ * + thinking tokens) and fold the `final` frame into a ParsedTurn.
4
+ *
5
+ * Defined over a structural `CompletionRunLike` (not the SDK type) so it stays
6
+ * SDK-free and unit-testable with a fake run — the real `CompletionRun` is
7
+ * assignable to it. The actual `@qvac/sdk` import lives in `provider.ts`.
8
+ */
9
+ import { type ParsedTurn, type QvacFinalLike } from './parse.js';
10
+ /** Minimal shape of a QVAC completion event we react to. */
11
+ export interface CompletionEventLike {
12
+ type: string;
13
+ /** Present on `contentDelta` / `thinkingDelta` / `rawDelta`. */
14
+ text?: string;
15
+ }
16
+ /** Structural subset of `completion()`'s return we depend on. */
17
+ export interface CompletionRunLike {
18
+ requestId: string;
19
+ events: AsyncIterable<CompletionEventLike>;
20
+ final: Promise<QvacFinalLike>;
21
+ }
22
+ export interface StreamHandlers {
23
+ /** Visible assistant tokens (excludes `<think>` reasoning). */
24
+ onToken?: (token: string) => void;
25
+ /** The model's `<think>` reasoning, streamed separately. */
26
+ onThinking?: (token: string) => void;
27
+ }
28
+ export interface ConsumedTurn extends ParsedTurn {
29
+ requestId: string;
30
+ }
31
+ /**
32
+ * Stream a run to completion. `contentDelta` → onToken (and the streamed
33
+ * fallback text), `thinkingDelta` → onThinking. Returns the parsed turn plus the
34
+ * run's `requestId` (for cancellation bookkeeping by the caller).
35
+ */
36
+ export declare function consumeRun(run: CompletionRunLike, handlers?: StreamHandlers): Promise<ConsumedTurn>;
37
+ //# sourceMappingURL=stream.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"stream.d.ts","sourceRoot":"","sources":["../../src/qvac/stream.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG;AACH,OAAO,EAAe,KAAK,UAAU,EAAE,KAAK,aAAa,EAAE,MAAM,YAAY,CAAC;AAE9E,4DAA4D;AAC5D,MAAM,WAAW,mBAAmB;IAClC,IAAI,EAAE,MAAM,CAAC;IACb,gEAAgE;IAChE,IAAI,CAAC,EAAE,MAAM,CAAC;CACf;AAED,iEAAiE;AACjE,MAAM,WAAW,iBAAiB;IAChC,SAAS,EAAE,MAAM,CAAC;IAClB,MAAM,EAAE,aAAa,CAAC,mBAAmB,CAAC,CAAC;IAC3C,KAAK,EAAE,OAAO,CAAC,aAAa,CAAC,CAAC;CAC/B;AAED,MAAM,WAAW,cAAc;IAC7B,+DAA+D;IAC/D,OAAO,CAAC,EAAE,CAAC,KAAK,EAAE,MAAM,KAAK,IAAI,CAAC;IAClC,4DAA4D;IAC5D,UAAU,CAAC,EAAE,CAAC,KAAK,EAAE,MAAM,KAAK,IAAI,CAAC;CACtC;AAED,MAAM,WAAW,YAAa,SAAQ,UAAU;IAC9C,SAAS,EAAE,MAAM,CAAC;CACnB;AAED;;;;GAIG;AACH,wBAAsB,UAAU,CAC9B,GAAG,EAAE,iBAAiB,EACtB,QAAQ,GAAE,cAAmB,GAC5B,OAAO,CAAC,YAAY,CAAC,CAYvB"}
@@ -0,0 +1,29 @@
1
+ /**
2
+ * Consume a QVAC `completion()` run: drain the event stream (forwarding visible
3
+ * + thinking tokens) and fold the `final` frame into a ParsedTurn.
4
+ *
5
+ * Defined over a structural `CompletionRunLike` (not the SDK type) so it stays
6
+ * SDK-free and unit-testable with a fake run — the real `CompletionRun` is
7
+ * assignable to it. The actual `@qvac/sdk` import lives in `provider.ts`.
8
+ */
9
+ import { finalToTurn } from './parse.js';
10
+ /**
11
+ * Stream a run to completion. `contentDelta` → onToken (and the streamed
12
+ * fallback text), `thinkingDelta` → onThinking. Returns the parsed turn plus the
13
+ * run's `requestId` (for cancellation bookkeeping by the caller).
14
+ */
15
+ export async function consumeRun(run, handlers = {}) {
16
+ let streamed = '';
17
+ for await (const event of run.events) {
18
+ if (event.type === 'contentDelta' && typeof event.text === 'string') {
19
+ streamed += event.text;
20
+ handlers.onToken?.(event.text);
21
+ }
22
+ else if (event.type === 'thinkingDelta' && typeof event.text === 'string') {
23
+ handlers.onThinking?.(event.text);
24
+ }
25
+ }
26
+ const final = await run.final;
27
+ return { ...finalToTurn(final, streamed), requestId: run.requestId };
28
+ }
29
+ //# sourceMappingURL=stream.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"stream.js","sourceRoot":"","sources":["../../src/qvac/stream.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG;AACH,OAAO,EAAE,WAAW,EAAuC,MAAM,YAAY,CAAC;AA2B9E;;;;GAIG;AACH,MAAM,CAAC,KAAK,UAAU,UAAU,CAC9B,GAAsB,EACtB,WAA2B,EAAE;IAE7B,IAAI,QAAQ,GAAG,EAAE,CAAC;IAClB,IAAI,KAAK,EAAE,MAAM,KAAK,IAAI,GAAG,CAAC,MAAM,EAAE,CAAC;QACrC,IAAI,KAAK,CAAC,IAAI,KAAK,cAAc,IAAI,OAAO,KAAK,CAAC,IAAI,KAAK,QAAQ,EAAE,CAAC;YACpE,QAAQ,IAAI,KAAK,CAAC,IAAI,CAAC;YACvB,QAAQ,CAAC,OAAO,EAAE,CAAC,KAAK,CAAC,IAAI,CAAC,CAAC;QACjC,CAAC;aAAM,IAAI,KAAK,CAAC,IAAI,KAAK,eAAe,IAAI,OAAO,KAAK,CAAC,IAAI,KAAK,QAAQ,EAAE,CAAC;YAC5E,QAAQ,CAAC,UAAU,EAAE,CAAC,KAAK,CAAC,IAAI,CAAC,CAAC;QACpC,CAAC;IACH,CAAC;IACD,MAAM,KAAK,GAAG,MAAM,GAAG,CAAC,KAAK,CAAC;IAC9B,OAAO,EAAE,GAAG,WAAW,CAAC,KAAK,EAAE,QAAQ,CAAC,EAAE,SAAS,EAAE,GAAG,CAAC,SAAS,EAAE,CAAC;AACvE,CAAC"}
@@ -0,0 +1,19 @@
1
+ /**
2
+ * Pure text helpers for QVAC output. No SDK, no platform — safe to run and test
3
+ * anywhere. Lifted verbatim from rate's QVACService so every host shares one
4
+ * implementation instead of drifting copies.
5
+ */
6
+ /**
7
+ * Clean a raw assistant completion into user-visible text:
8
+ * - drop `<think>…</think>` reasoning (small models leak it into content),
9
+ * - drop a leading `{"name":…,"arguments":…}` tool-call object some tiny models
10
+ * emit as plain text, keeping any natural-language sentence that follows.
11
+ */
12
+ export declare function cleanAssistantVisibleText(text: string): string;
13
+ /**
14
+ * Make text safe for the SUPERTONIC TTS model: redact payment strings (so they
15
+ * are never read aloud), strip markdown/code, normalize smart punctuation, and
16
+ * drop any non-ASCII or backtick (U+0060) the model can't synthesize.
17
+ */
18
+ export declare function sanitizeForSupertonic(text: string): string;
19
+ //# sourceMappingURL=text.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"text.d.ts","sourceRoot":"","sources":["../../src/qvac/text.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAEH;;;;;GAKG;AACH,wBAAgB,yBAAyB,CAAC,IAAI,EAAE,MAAM,GAAG,MAAM,CAkB9D;AAED;;;;GAIG;AACH,wBAAgB,qBAAqB,CAAC,IAAI,EAAE,MAAM,GAAG,MAAM,CAsB1D"}
@@ -0,0 +1,56 @@
1
+ /**
2
+ * Pure text helpers for QVAC output. No SDK, no platform — safe to run and test
3
+ * anywhere. Lifted verbatim from rate's QVACService so every host shares one
4
+ * implementation instead of drifting copies.
5
+ */
6
+ /**
7
+ * Clean a raw assistant completion into user-visible text:
8
+ * - drop `<think>…</think>` reasoning (small models leak it into content),
9
+ * - drop a leading `{"name":…,"arguments":…}` tool-call object some tiny models
10
+ * emit as plain text, keeping any natural-language sentence that follows.
11
+ */
12
+ export function cleanAssistantVisibleText(text) {
13
+ let cleaned = text
14
+ // Qwen-style reasoning sometimes arrives in contentText. Never show/speak it.
15
+ .replace(/<think\b[\s\S]*?<\/think>/gi, ' ')
16
+ .replace(/<think\b[\s\S]*$/gi, ' ')
17
+ .replace(/\s+/g, ' ')
18
+ .trim();
19
+ // Some small local models emit a tool-call object as plain text. Drop the
20
+ // leading fragment and keep any natural-language sentence that follows.
21
+ const toolPrefix = cleaned.match(/^\s*\{?\s*"name"\s*:\s*"[^"]+"\s*,\s*"arguments"\s*:\s*/i);
22
+ if (toolPrefix) {
23
+ cleaned = cleaned.slice(toolPrefix[0].length).replace(/^\s*\{?\s*/, '').trim();
24
+ }
25
+ return cleaned
26
+ .replace(/\s+/g, ' ')
27
+ .trim();
28
+ }
29
+ /**
30
+ * Make text safe for the SUPERTONIC TTS model: redact payment strings (so they
31
+ * are never read aloud), strip markdown/code, normalize smart punctuation, and
32
+ * drop any non-ASCII or backtick (U+0060) the model can't synthesize.
33
+ */
34
+ export function sanitizeForSupertonic(text) {
35
+ const normalized = text
36
+ .replace(/\b(?:lightning:)?ln(?:bc|tb|bcrt)[a-z0-9]{40,}\b/gi, 'Lightning invoice')
37
+ .replace(/\blnurl[0-9a-z]{40,}\b/gi, 'Lightning payment link')
38
+ .replace(/```[\s\S]*?```/g, ' ')
39
+ .replace(/`([^`]*)`/g, '$1')
40
+ .replace(/[`´ˋ′*_~#<>|[\]{}]/g, ' ')
41
+ .replace(/[“”]/g, '"')
42
+ .replace(/[‘’]/g, "'")
43
+ .replace(/[•·]/g, '. ')
44
+ .replace(/[^\x09\x0A\x0D\x20-\x7E]/g, ' ')
45
+ .replace(/\s+/g, ' ');
46
+ return Array.from(normalized)
47
+ .filter((ch) => {
48
+ const code = ch.charCodeAt(0);
49
+ return (code === 0x09 || code === 0x0A || code === 0x0D || (code >= 0x20 && code <= 0x7E)) &&
50
+ code !== 0x60;
51
+ })
52
+ .join('')
53
+ .replace(/\s+/g, ' ')
54
+ .trim();
55
+ }
56
+ //# sourceMappingURL=text.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"text.js","sourceRoot":"","sources":["../../src/qvac/text.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAEH;;;;;GAKG;AACH,MAAM,UAAU,yBAAyB,CAAC,IAAY;IACpD,IAAI,OAAO,GAAG,IAAI;QAChB,8EAA8E;SAC7E,OAAO,CAAC,6BAA6B,EAAE,GAAG,CAAC;SAC3C,OAAO,CAAC,oBAAoB,EAAE,GAAG,CAAC;SAClC,OAAO,CAAC,MAAM,EAAE,GAAG,CAAC;SACpB,IAAI,EAAE,CAAC;IAEV,0EAA0E;IAC1E,wEAAwE;IACxE,MAAM,UAAU,GAAG,OAAO,CAAC,KAAK,CAAC,0DAA0D,CAAC,CAAC;IAC7F,IAAI,UAAU,EAAE,CAAC;QACf,OAAO,GAAG,OAAO,CAAC,KAAK,CAAC,UAAU,CAAC,CAAC,CAAC,CAAC,MAAM,CAAC,CAAC,OAAO,CAAC,YAAY,EAAE,EAAE,CAAC,CAAC,IAAI,EAAE,CAAC;IACjF,CAAC;IAED,OAAO,OAAO;SACX,OAAO,CAAC,MAAM,EAAE,GAAG,CAAC;SACpB,IAAI,EAAE,CAAC;AACZ,CAAC;AAED;;;;GAIG;AACH,MAAM,UAAU,qBAAqB,CAAC,IAAY;IAChD,MAAM,UAAU,GAAG,IAAI;SACpB,OAAO,CAAC,oDAAoD,EAAE,mBAAmB,CAAC;SAClF,OAAO,CAAC,0BAA0B,EAAE,wBAAwB,CAAC;SAC7D,OAAO,CAAC,iBAAiB,EAAE,GAAG,CAAC;SAC/B,OAAO,CAAC,YAAY,EAAE,IAAI,CAAC;SAC3B,OAAO,CAAC,qBAAqB,EAAE,GAAG,CAAC;SACnC,OAAO,CAAC,OAAO,EAAE,GAAG,CAAC;SACrB,OAAO,CAAC,OAAO,EAAE,GAAG,CAAC;SACrB,OAAO,CAAC,OAAO,EAAE,IAAI,CAAC;SACtB,OAAO,CAAC,2BAA2B,EAAE,GAAG,CAAC;SACzC,OAAO,CAAC,MAAM,EAAE,GAAG,CAAC,CAAC;IAExB,OAAO,KAAK,CAAC,IAAI,CAAC,UAAU,CAAC;SAC1B,MAAM,CAAC,CAAC,EAAE,EAAE,EAAE;QACb,MAAM,IAAI,GAAG,EAAE,CAAC,UAAU,CAAC,CAAC,CAAC,CAAC;QAC9B,OAAO,CAAC,IAAI,KAAK,IAAI,IAAI,IAAI,KAAK,IAAI,IAAI,IAAI,KAAK,IAAI,IAAI,CAAC,IAAI,IAAI,IAAI,IAAI,IAAI,IAAI,IAAI,CAAC,CAAC;YACxF,IAAI,KAAK,IAAI,CAAC;IAClB,CAAC,CAAC;SACD,IAAI,CAAC,EAAE,CAAC;SACR,OAAO,CAAC,MAAM,EAAE,GAAG,CAAC;SACpB,IAAI,EAAE,CAAC;AACZ,CAAC"}
@@ -0,0 +1,69 @@
1
+ /**
2
+ * Voice runtime ops shared across hosts: one-shot transcription (Whisper) and
3
+ * speech synthesis (SUPERTONIC TTS). Like the provider, the SDK functions are
4
+ * injected (type-only `@qvac/sdk` import, erased at build) so this carries no
5
+ * runtime SDK dependency and is unit-testable with fakes.
6
+ *
7
+ * The host still owns model lifecycle (download, load, local-vs-delegated) and
8
+ * audio I/O (mic capture, playback). It passes the loaded model-id resolvers;
9
+ * this module does the SDK calls + the text gating that must be identical
10
+ * everywhere (payment-string redaction, U+0060 refusal, file:// stripping).
11
+ *
12
+ * The streaming voice-assistant loop (transcribeStream + VAD) builds on top of
13
+ * these in a later pass.
14
+ */
15
+ import type * as QvacSdk from '@qvac/sdk';
16
+ import type { VoiceTranscriptEvent } from './assistant.js';
17
+ type TranscribeFn = typeof QvacSdk.transcribe;
18
+ type TextToSpeechFn = typeof QvacSdk.textToSpeech;
19
+ type TranscribeStreamFn = typeof QvacSdk.transcribeStream;
20
+ /** 16-bit PCM samples plus their sample rate, ready for the host to play. */
21
+ export interface PcmAudio {
22
+ pcm: number[];
23
+ sampleRate: number;
24
+ }
25
+ /**
26
+ * A live VAD transcription session: feed mic audio with `write()`, iterate to
27
+ * receive `text`/`vad`/`endOfTurn` events, `end()` when audio stops. Pass it
28
+ * straight to `runVoiceAssistant`.
29
+ */
30
+ export interface VoiceSession {
31
+ write(audioChunk: Uint8Array): void;
32
+ end(): void;
33
+ destroy(): void;
34
+ [Symbol.asyncIterator](): AsyncIterator<VoiceTranscriptEvent>;
35
+ }
36
+ export interface QvacVoiceOptions {
37
+ /** The SDK's `transcribe` (injected). */
38
+ transcribe: TranscribeFn;
39
+ /** The SDK's `textToSpeech` (injected). */
40
+ textToSpeech: TextToSpeechFn;
41
+ /** The SDK's `transcribeStream` (injected) — only needed for `openVoiceSession`. */
42
+ transcribeStream?: TranscribeStreamFn;
43
+ /** Resolve the loaded Whisper model id (null ⇒ not loaded → throws). */
44
+ getWhisperModelId: () => string | null;
45
+ /** Resolve the loaded TTS model id (null ⇒ not loaded → returns null). */
46
+ getTtsModelId: () => string | null;
47
+ /** TTS output sample rate; defaults to SUPERTONIC-2's 44.1 kHz. */
48
+ ttsSampleRate?: number;
49
+ }
50
+ export interface QvacVoice {
51
+ /** Transcribe an audio file (path or `file://` URI) to text. */
52
+ transcribeAudio(audioUri: string): Promise<string>;
53
+ /**
54
+ * Synthesize speech for `text`. Returns PCM + sample rate, or `null` when TTS
55
+ * is unavailable or the text is empty after sanitization (host falls back to
56
+ * the system voice). Payment strings are redacted so they're never read aloud.
57
+ */
58
+ synthesizeSpeech(text: string): Promise<PcmAudio | null>;
59
+ /**
60
+ * Open a hands-free VAD transcription session (continuous voice). Requires
61
+ * `transcribeStream` to have been provided. Merge in `paramsOverride` to tune
62
+ * the defaults ({@link DEFAULT_VOICE_STREAM_PARAMS}). Feed the returned session
63
+ * to `runVoiceAssistant`.
64
+ */
65
+ openVoiceSession(paramsOverride?: Record<string, unknown>): Promise<VoiceSession>;
66
+ }
67
+ export declare function createQvacVoice(options: QvacVoiceOptions): QvacVoice;
68
+ export {};
69
+ //# sourceMappingURL=voice.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"voice.d.ts","sourceRoot":"","sources":["../../src/qvac/voice.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;GAaG;AACH,OAAO,KAAK,KAAK,OAAO,MAAM,WAAW,CAAC;AAG1C,OAAO,KAAK,EAAE,oBAAoB,EAAE,MAAM,gBAAgB,CAAC;AAE3D,KAAK,YAAY,GAAG,OAAO,OAAO,CAAC,UAAU,CAAC;AAC9C,KAAK,cAAc,GAAG,OAAO,OAAO,CAAC,YAAY,CAAC;AAClD,KAAK,kBAAkB,GAAG,OAAO,OAAO,CAAC,gBAAgB,CAAC;AAE1D,6EAA6E;AAC7E,MAAM,WAAW,QAAQ;IACvB,GAAG,EAAE,MAAM,EAAE,CAAC;IACd,UAAU,EAAE,MAAM,CAAC;CACpB;AAED;;;;GAIG;AACH,MAAM,WAAW,YAAY;IAC3B,KAAK,CAAC,UAAU,EAAE,UAAU,GAAG,IAAI,CAAC;IACpC,GAAG,IAAI,IAAI,CAAC;IACZ,OAAO,IAAI,IAAI,CAAC;IAChB,CAAC,MAAM,CAAC,aAAa,CAAC,IAAI,aAAa,CAAC,oBAAoB,CAAC,CAAC;CAC/D;AAED,MAAM,WAAW,gBAAgB;IAC/B,yCAAyC;IACzC,UAAU,EAAE,YAAY,CAAC;IACzB,2CAA2C;IAC3C,YAAY,EAAE,cAAc,CAAC;IAC7B,oFAAoF;IACpF,gBAAgB,CAAC,EAAE,kBAAkB,CAAC;IACtC,wEAAwE;IACxE,iBAAiB,EAAE,MAAM,MAAM,GAAG,IAAI,CAAC;IACvC,0EAA0E;IAC1E,aAAa,EAAE,MAAM,MAAM,GAAG,IAAI,CAAC;IACnC,mEAAmE;IACnE,aAAa,CAAC,EAAE,MAAM,CAAC;CACxB;AAED,MAAM,WAAW,SAAS;IACxB,gEAAgE;IAChE,eAAe,CAAC,QAAQ,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,CAAC,CAAC;IACnD;;;;OAIG;IACH,gBAAgB,CAAC,IAAI,EAAE,MAAM,GAAG,OAAO,CAAC,QAAQ,GAAG,IAAI,CAAC,CAAC;IACzD;;;;;OAKG;IACH,gBAAgB,CAAC,cAAc,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAAG,OAAO,CAAC,YAAY,CAAC,CAAC;CACnF;AAED,wBAAgB,eAAe,CAAC,OAAO,EAAE,gBAAgB,GAAG,SAAS,CA+CpE"}
@@ -0,0 +1,51 @@
1
+ import { sanitizeForSupertonic } from './text.js';
2
+ import { TTS_SAMPLE_RATE, DEFAULT_VOICE_STREAM_PARAMS } from './config.js';
3
+ export function createQvacVoice(options) {
4
+ const sampleRate = options.ttsSampleRate ?? TTS_SAMPLE_RATE;
5
+ return {
6
+ async transcribeAudio(audioUri) {
7
+ const modelId = options.getWhisperModelId();
8
+ if (!modelId)
9
+ throw new Error('Whisper model not loaded');
10
+ // The SDK's native file reader wants a plain filesystem path, not a
11
+ // `file://` URI — the URI raises AUDIO_FILE_NOT_FOUND even when present.
12
+ const audioChunk = audioUri.replace('file://', '');
13
+ return await options.transcribe({ modelId, audioChunk });
14
+ },
15
+ async synthesizeSpeech(text) {
16
+ const modelId = options.getTtsModelId();
17
+ if (!modelId)
18
+ return null;
19
+ const trimmed = sanitizeForSupertonic(text);
20
+ if (!trimmed)
21
+ return null;
22
+ // Belt-and-suspenders: SUPERTONIC chokes on U+0060; sanitize already
23
+ // strips it, so refuse if any slipped through rather than crash the voice.
24
+ if (Array.from(trimmed).some((ch) => ch.charCodeAt(0) === 0x60))
25
+ return null;
26
+ const result = options.textToSpeech({
27
+ modelId,
28
+ text: trimmed,
29
+ inputType: 'text',
30
+ stream: false,
31
+ });
32
+ const pcm = await result.buffer;
33
+ return { pcm, sampleRate };
34
+ },
35
+ async openVoiceSession(paramsOverride = {}) {
36
+ if (!options.transcribeStream) {
37
+ throw new Error('transcribeStream not provided — pass it in QvacVoiceOptions for voice sessions');
38
+ }
39
+ const modelId = options.getWhisperModelId();
40
+ if (!modelId)
41
+ throw new Error('Whisper model not loaded');
42
+ const session = await options.transcribeStream({
43
+ modelId,
44
+ ...DEFAULT_VOICE_STREAM_PARAMS,
45
+ ...paramsOverride,
46
+ });
47
+ return session;
48
+ },
49
+ };
50
+ }
51
+ //# sourceMappingURL=voice.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"voice.js","sourceRoot":"","sources":["../../src/qvac/voice.ts"],"names":[],"mappings":"AAeA,OAAO,EAAE,qBAAqB,EAAE,MAAM,WAAW,CAAC;AAClD,OAAO,EAAE,eAAe,EAAE,2BAA2B,EAAE,MAAM,aAAa,CAAC;AA0D3E,MAAM,UAAU,eAAe,CAAC,OAAyB;IACvD,MAAM,UAAU,GAAG,OAAO,CAAC,aAAa,IAAI,eAAe,CAAC;IAE5D,OAAO;QACL,KAAK,CAAC,eAAe,CAAC,QAAgB;YACpC,MAAM,OAAO,GAAG,OAAO,CAAC,iBAAiB,EAAE,CAAC;YAC5C,IAAI,CAAC,OAAO;gBAAE,MAAM,IAAI,KAAK,CAAC,0BAA0B,CAAC,CAAC;YAC1D,oEAAoE;YACpE,yEAAyE;YACzE,MAAM,UAAU,GAAG,QAAQ,CAAC,OAAO,CAAC,SAAS,EAAE,EAAE,CAAC,CAAC;YACnD,OAAO,MAAM,OAAO,CAAC,UAAU,CAAC,EAAE,OAAO,EAAE,UAAU,EAAiC,CAAC,CAAC;QAC1F,CAAC;QAED,KAAK,CAAC,gBAAgB,CAAC,IAAY;YACjC,MAAM,OAAO,GAAG,OAAO,CAAC,aAAa,EAAE,CAAC;YACxC,IAAI,CAAC,OAAO;gBAAE,OAAO,IAAI,CAAC;YAE1B,MAAM,OAAO,GAAG,qBAAqB,CAAC,IAAI,CAAC,CAAC;YAC5C,IAAI,CAAC,OAAO;gBAAE,OAAO,IAAI,CAAC;YAC1B,qEAAqE;YACrE,2EAA2E;YAC3E,IAAI,KAAK,CAAC,IAAI,CAAC,OAAO,CAAC,CAAC,IAAI,CAAC,CAAC,EAAE,EAAE,EAAE,CAAC,EAAE,CAAC,UAAU,CAAC,CAAC,CAAC,KAAK,IAAI,CAAC;gBAAE,OAAO,IAAI,CAAC;YAE7E,MAAM,MAAM,GAAG,OAAO,CAAC,YAAY,CAAC;gBAClC,OAAO;gBACP,IAAI,EAAE,OAAO;gBACb,SAAS,EAAE,MAAM;gBACjB,MAAM,EAAE,KAAK;aACmB,CAAC,CAAC;YACpC,MAAM,GAAG,GAAG,MAAM,MAAM,CAAC,MAAM,CAAC;YAChC,OAAO,EAAE,GAAG,EAAE,UAAU,EAAE,CAAC;QAC7B,CAAC;QAED,KAAK,CAAC,gBAAgB,CAAC,iBAA0C,EAAE;YACjE,IAAI,CAAC,OAAO,CAAC,gBAAgB,EAAE,CAAC;gBAC9B,MAAM,IAAI,KAAK,CAAC,gFAAgF,CAAC,CAAC;YACpG,CAAC;YACD,MAAM,OAAO,GAAG,OAAO,CAAC,iBAAiB,EAAE,CAAC;YAC5C,IAAI,CAAC,OAAO;gBAAE,MAAM,IAAI,KAAK,CAAC,0BAA0B,CAAC,CAAC;YAC1D,MAAM,OAAO,GAAG,MAAM,OAAO,CAAC,gBAAgB,CAAC;gBAC7C,OAAO;gBACP,GAAG,2BAA2B;gBAC9B,GAAG,cAAc;aACmB,CAAC,CAAC;YACxC,OAAO,OAAkC,CAAC;QAC5C,CAAC;KACF,CAAC;AACJ,CAAC"}
@@ -0,0 +1,26 @@
1
+ /**
2
+ * Built-in "buy an asset channel" recipe — the onboarding buy.
3
+ *
4
+ * The user has on-chain BTC but no Lightning channel yet, and wants to HOLD an
5
+ * RGB asset (USDT, XAUT). They can't swap (no channel to swap inside), so they
6
+ * buy a NEW channel from the maker LSP pre-loaded with the asset. One quote,
7
+ * one spend:
8
+ *
9
+ * "buy 100 usdt" / "get me 50 xaut" / "i want 200 usdt"
10
+ * ↓ 1 model inference (slot extraction; 0 when the regex hits)
11
+ * kaleidoswap_lsp_quote_asset_channel ← maker prices the asset + channel
12
+ * kaleidoswap_lsp_create_asset_channel 🔒 ← (final) order it; pay to open
13
+ *
14
+ * Distinct from `swapRecipe`: a swap names a source asset ("swap 10 usdt FOR
15
+ * btc", "buy btc WITH usdt") and needs an existing channel. This is the
16
+ * no-source, no-channel onboarding path — "buy <amount> <asset>" with nothing
17
+ * to spend it from — so it must be SELECTED BEFORE swap for that phrasing.
18
+ *
19
+ * Opt-in: register via `Funnel.recipes` (like `kaleidoswapAtomicRecipe`). The
20
+ * host binds `kaleidoswap_lsp_*` to its transport (maker REST / MCP / WDK).
21
+ */
22
+ import type { Recipe } from './types.js';
23
+ /** "buy 100 usdt" / "get me 50 xaut" / "i want 200 usdt" / "purchase 10 xaut". */
24
+ export declare function extractBuyAsset(text: string): Record<string, unknown> | null;
25
+ export declare const buyAssetChannelRecipe: Recipe;
26
+ //# sourceMappingURL=buy-asset-channel.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"buy-asset-channel.d.ts","sourceRoot":"","sources":["../../src/recipe/buy-asset-channel.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;GAoBG;AAEH,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,YAAY,CAAC;AA4BzC,kFAAkF;AAClF,wBAAgB,eAAe,CAAC,IAAI,EAAE,MAAM,GAAG,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAAG,IAAI,CAW5E;AAED,eAAO,MAAM,qBAAqB,EAAE,MAqDnC,CAAC"}
@@ -0,0 +1,112 @@
1
+ /**
2
+ * Built-in "buy an asset channel" recipe — the onboarding buy.
3
+ *
4
+ * The user has on-chain BTC but no Lightning channel yet, and wants to HOLD an
5
+ * RGB asset (USDT, XAUT). They can't swap (no channel to swap inside), so they
6
+ * buy a NEW channel from the maker LSP pre-loaded with the asset. One quote,
7
+ * one spend:
8
+ *
9
+ * "buy 100 usdt" / "get me 50 xaut" / "i want 200 usdt"
10
+ * ↓ 1 model inference (slot extraction; 0 when the regex hits)
11
+ * kaleidoswap_lsp_quote_asset_channel ← maker prices the asset + channel
12
+ * kaleidoswap_lsp_create_asset_channel 🔒 ← (final) order it; pay to open
13
+ *
14
+ * Distinct from `swapRecipe`: a swap names a source asset ("swap 10 usdt FOR
15
+ * btc", "buy btc WITH usdt") and needs an existing channel. This is the
16
+ * no-source, no-channel onboarding path — "buy <amount> <asset>" with nothing
17
+ * to spend it from — so it must be SELECTED BEFORE swap for that phrasing.
18
+ *
19
+ * Opt-in: register via `Funnel.recipes` (like `kaleidoswapAtomicRecipe`). The
20
+ * host binds `kaleidoswap_lsp_*` to its transport (maker REST / MCP / WDK).
21
+ */
22
+ /** RGB assets the maker sells as an asset channel. BTC is never "bought" this way. */
23
+ const RGB_ASSET = /\b(usdt|tether|xaut|gold)\b/i;
24
+ /** A named funding source ⇒ this is a swap, not an onboarding buy. */
25
+ const HAS_SOURCE = /\b(?:with|using|from)\b|\bfor\s+(?:btc|bitcoin|sats?|usdt|xaut|tether|gold)\b/i;
26
+ /** Verbs other intents own (swap / sell / send) — never an onboarding buy. */
27
+ const NOT_BUY = /\b(swap|exchange|convert|trade|sell|send)\b/i;
28
+ /** Acquire verbs that DO mean an onboarding buy. */
29
+ const BUY_VERB = /\b(buy|get|acquire|want|purchase|onboard|need)\b/i;
30
+ function normAsset(a) {
31
+ if (!a)
32
+ return undefined;
33
+ const x = a.toLowerCase();
34
+ if (/usdt|tether/.test(x))
35
+ return 'USDT';
36
+ if (/xaut|gold/.test(x))
37
+ return 'XAUT';
38
+ return undefined;
39
+ }
40
+ const num = (s) => {
41
+ if (!s)
42
+ return undefined;
43
+ const n = Number(s.replace(/,/g, ''));
44
+ return Number.isFinite(n) ? n : undefined;
45
+ };
46
+ /** Thousands separators, locale-independent (deterministic for tests). */
47
+ const commas = (n) => String(n).replace(/\B(?=(\d{3})+(?!\d))/g, ',');
48
+ /** "buy 100 usdt" / "get me 50 xaut" / "i want 200 usdt" / "purchase 10 xaut". */
49
+ export function extractBuyAsset(text) {
50
+ const t = text.trim();
51
+ if (NOT_BUY.test(t) || HAS_SOURCE.test(t))
52
+ return null;
53
+ if (!RGB_ASSET.test(t))
54
+ return null;
55
+ // buy/get/want/acquire/purchase [me] <amount> <asset>
56
+ const m = t.match(/\b(?:buy|get|acquire|want|purchase|onboard|need)\b(?:\s+me)?\s+([\d.,]+)\s*([a-z]+)/i);
57
+ if (!m)
58
+ return null;
59
+ const asset = normAsset(m[2]);
60
+ const amount = num(m[1]);
61
+ if (!asset || amount === undefined)
62
+ return null;
63
+ return { asset, asset_amount: amount };
64
+ }
65
+ export const buyAssetChannelRecipe = {
66
+ name: 'buy-asset-channel',
67
+ description: 'Onboarding buy: purchase a new Lightning channel pre-loaded with an RGB asset (USDT, XAUT) from the maker LSP — for a user with on-chain BTC but no channel yet. Quote, then order (with confirmation).',
68
+ // "buy/get/want N <rgb-asset>" with NO named source asset and NO swap/send verb.
69
+ match: (t) => !NOT_BUY.test(t) && !HAS_SOURCE.test(t) && RGB_ASSET.test(t) && BUY_VERB.test(t),
70
+ triggers: ['buy', 'get', 'purchase', 'acquire'],
71
+ slots: [
72
+ { name: 'asset', type: 'string', description: 'RGB asset to acquire (USDT or XAUT)', required: true },
73
+ { name: 'asset_amount', type: 'number', description: 'Amount of the asset to load into the channel (display units, e.g. 100)', required: true },
74
+ ],
75
+ extract: extractBuyAsset,
76
+ confident: (s) => !!s.asset && s.asset_amount !== undefined && Number(s.asset_amount) > 0,
77
+ steps: [
78
+ // 1. Maker prices the asset + the channel.
79
+ // Returns { rfq_id, btc_amount_sat, channel_fee_sat, total_sat, expires_at }.
80
+ {
81
+ tool: 'kaleidoswap_lsp_quote_asset_channel',
82
+ as: 'quote',
83
+ args: (ctx) => ({ asset: ctx.slots.asset, asset_amount: ctx.slots.asset_amount }),
84
+ },
85
+ ],
86
+ // 2. Order the channel with the fresh rfq_id. Spend → confirmation-gated.
87
+ // The quote's cost fields ride along so the host's confirm card can show
88
+ // the price before approval; the create tool treats them as display-only.
89
+ final: {
90
+ tool: 'kaleidoswap_lsp_create_asset_channel',
91
+ args: (ctx) => {
92
+ const q = (ctx.results.quote ?? {});
93
+ return {
94
+ asset: ctx.slots.asset,
95
+ asset_amount: ctx.slots.asset_amount,
96
+ rfq_id: q.rfq_id,
97
+ total_sat: q.total_sat,
98
+ btc_amount_sat: q.btc_amount_sat,
99
+ channel_fee_sat: q.channel_fee_sat,
100
+ expires_at: q.expires_at,
101
+ };
102
+ },
103
+ },
104
+ summary: (ctx, finalResult) => {
105
+ const q = ctx.results.quote;
106
+ const o = finalResult;
107
+ const cost = typeof q?.total_sat === 'number' ? ` for ${commas(q.total_sat)} sats` : '';
108
+ const id = o?.order_id ? ` (order ${o.order_id})` : '';
109
+ return `Ordered a Lightning channel with ${ctx.slots.asset_amount} ${ctx.slots.asset}${cost}${id}. Pay the returned invoice/address to open it.`;
110
+ },
111
+ };
112
+ //# sourceMappingURL=buy-asset-channel.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"buy-asset-channel.js","sourceRoot":"","sources":["../../src/recipe/buy-asset-channel.ts"],"names":[],"mappings":"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"}
@@ -1,26 +1,34 @@
1
1
  /**
2
- * Built-in "atomic swap on KaleidoSwap" recipe — trust-minimised chain.
2
+ * Built-in "swap on KaleidoSwap" recipe — the real atomic-swap chain.
3
3
  *
4
- * Most users want the simple market-order swap (`swapRecipe` over generic
5
- * `get_swap_quote` / `execute_swap`). This recipe is the EXPLICIT atomic path:
6
- * the user creates an RGB/LN receive invoice, the maker locks the swap, the
7
- * user pays the maker's Lightning invoice, and the maker releases.
4
+ * A swap (especially the full maker + RLN atomic) is a 6-step, two-service flow
5
+ * no small model can plan reliably, so the recipe carries the plan. The model
6
+ * is used for natural-language understanding of the request (slot extraction).
8
7
  *
9
- * Triggered only by explicit atomic-swap intent ("atomic swap", "trustless
10
- * swap", "htlc swap") so it never preempts the simpler swap path for vague
11
- * phrasings.
8
+ * "buy 1 usdt" (or "swap 10 usdt to btc")
9
+ * heuristic pre-filter (0 inf) decides to enter the reliable recipe branch
10
+ * 1 model inference (forced LLM slot extraction — the model parses intent)
11
+ * kaleidoswap_get_quote ← MAKER prices the swap (read-only)
12
+ * ↓ [ONE confirmation gate — shows the real quote numbers]
13
+ * kaleidoswap_atomic_init ← MAKER locks the swap → swapstring, payment_hash
14
+ * rln_get_node_info ← NODE read pubkey (= taker_pubkey)
15
+ * rln_whitelist_swap ← NODE accept the swapstring
16
+ * kaleidoswap_atomic_execute ← MAKER settle (final)
12
17
  *
13
- * "atomic swap 100000 sats for usdt"
14
- * 1 model inference (slot extraction)
15
- * kaleidoswap_get_quote ← maker prices the swap
16
- * rln_create_rgb_invoice ← user's node prepares receive (if to_asset is RGB)
17
- * rln_create_ln_invoice ← (alt) if to_asset is BTC
18
- * kaleidoswap_atomic_init 🔒 ← maker locks the swap, returns its invoice
19
- * rln_pay_invoice 🔒 ← user pays the maker
20
- * kaleidoswap_atomic_execute 🔒 ← (final) maker releases the asset
18
+ * `forceModelExtract` ensures the model is always consulted for slot parsing
19
+ * (1 inference) so natural language like "buy 1 usdt" is interpreted by the LLM.
20
+ * A safety fallback in the runner uses the deterministic extractor if the model
21
+ * returns incomplete slots. The execution sequence + single-confirm gate remain
22
+ * fully deterministic and reliable.
21
23
  *
22
- * Two-or-three confirmation gates are intentional: each represents a distinct
23
- * decision point. The host's confirm UI describes what's about to happen.
24
+ * Status is NOT polled here settlement takes seconds-to-minutes and blocking
25
+ * the chat is bad UX. The recipe reports "submitted, settling"; the user (or a
26
+ * follow-up turn) calls `kaleidoswap_atomic_status` on demand.
27
+ *
28
+ * Confirmation: the single decision a user makes is "given this quote, proceed?"
29
+ * — so the recipe declares ONE `confirm(ctx)` summary, fired after the quote and
30
+ * before init. init/whitelist/execute then run as one approved unit. (The
31
+ * runner's recipe-level confirm path handles this; see recipe/runner.ts.)
24
32
  */
25
33
  import type { Recipe } from './types.js';
26
34
  export declare const kaleidoswapAtomicRecipe: Recipe;
@@ -1 +1 @@
1
- {"version":3,"file":"kaleidoswap-atomic.d.ts","sourceRoot":"","sources":["../../src/recipe/kaleidoswap-atomic.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;GAuBG;AAEH,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,YAAY,CAAC;AAUzC,eAAO,MAAM,uBAAuB,EAAE,MAiFrC,CAAC"}
1
+ {"version":3,"file":"kaleidoswap-atomic.d.ts","sourceRoot":"","sources":["../../src/recipe/kaleidoswap-atomic.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA+BG;AAEH,OAAO,KAAK,EAAE,MAAM,EAAiB,MAAM,YAAY,CAAC;AAkCxD,eAAO,MAAM,uBAAuB,EAAE,MA+FrC,CAAC"}