@tangle-network/agent-app 0.29.0 → 0.31.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 (44) hide show
  1. package/dist/{DesignCanvasEditor-IB2FMBBD.js → DesignCanvasEditor-QQNAZRJQ.js} +3 -3
  2. package/dist/IntakeInterview-WHVKMNQW.js +8 -0
  3. package/dist/IntakeInterview-WHVKMNQW.js.map +1 -0
  4. package/dist/chunk-4K7BZYO7.js +124 -0
  5. package/dist/chunk-4K7BZYO7.js.map +1 -0
  6. package/dist/chunk-5I72FRZY.js +212 -0
  7. package/dist/chunk-5I72FRZY.js.map +1 -0
  8. package/dist/{chunk-S5CAJX6O.js → chunk-FJUOBNIY.js} +2 -2
  9. package/dist/{chunk-Y2SZVW35.js → chunk-LVD37K5V.js} +41 -41
  10. package/dist/chunk-LVD37K5V.js.map +1 -0
  11. package/dist/chunk-ND3XEGBE.js +119 -0
  12. package/dist/chunk-ND3XEGBE.js.map +1 -0
  13. package/dist/chunk-USYXHDKE.js +30 -0
  14. package/dist/chunk-USYXHDKE.js.map +1 -0
  15. package/dist/{chunk-N4ZFKQ5C.js → chunk-YYYXGLLQ.js} +2 -2
  16. package/dist/design-canvas-react/index.js +3 -3
  17. package/dist/design-canvas-react/lazy.js +1 -1
  18. package/dist/index.js +1 -1
  19. package/dist/intakes/api.d.ts +59 -0
  20. package/dist/intakes/api.js +63 -0
  21. package/dist/intakes/api.js.map +1 -0
  22. package/dist/intakes/drizzle.d.ts +385 -0
  23. package/dist/intakes/drizzle.js +61 -0
  24. package/dist/intakes/drizzle.js.map +1 -0
  25. package/dist/intakes/index.d.ts +42 -0
  26. package/dist/intakes/index.js +31 -0
  27. package/dist/intakes/index.js.map +1 -0
  28. package/dist/intakes-react/index.d.ts +48 -0
  29. package/dist/intakes-react/index.js +8 -0
  30. package/dist/intakes-react/index.js.map +1 -0
  31. package/dist/intakes-react/lazy.d.ts +8 -0
  32. package/dist/intakes-react/lazy.js +9 -0
  33. package/dist/intakes-react/lazy.js.map +1 -0
  34. package/dist/model-Cuj7d-xT.d.ts +116 -0
  35. package/dist/theme/index.js +1 -1
  36. package/dist/theme/tokens.css +50 -48
  37. package/dist/web-react/index.d.ts +6 -1
  38. package/dist/web-react/index.js +8 -14
  39. package/dist/web-react/index.js.map +1 -1
  40. package/package.json +26 -1
  41. package/dist/chunk-Y2SZVW35.js.map +0 -1
  42. /package/dist/{DesignCanvasEditor-IB2FMBBD.js.map → DesignCanvasEditor-QQNAZRJQ.js.map} +0 -0
  43. /package/dist/{chunk-S5CAJX6O.js.map → chunk-FJUOBNIY.js.map} +0 -0
  44. /package/dist/{chunk-N4ZFKQ5C.js.map → chunk-YYYXGLLQ.js.map} +0 -0
@@ -0,0 +1,116 @@
1
+ /**
2
+ * Pure intake MODEL — the question-graph and the answer/completion algebra a
3
+ * one-question-at-a-time interview runs on. Zero dependencies: no drizzle, no
4
+ * env, no react, no I/O. The DB layer (`./intakes/drizzle`), the handlers
5
+ * (`./intakes/api`) and the React surface (`./intakes-react`) all build on
6
+ * these functions; this leaf imports nothing back, so a consumer can pull just
7
+ * the intake math.
8
+ *
9
+ * An intake is an ordered list of questions, optionally branching: a question
10
+ * can declare `next` as a function of the answers so far, so the next prompt
11
+ * depends on what was said (e.g. "do you have a website?" → no → skip the URL
12
+ * question). Traversal is pure and deterministic — `nextQuestion(graph, answers)`
13
+ * folds the answers into the single question to ask next (or null = done), and
14
+ * `isComplete` is true exactly when every REQUIRED reachable question has a
15
+ * valid answer.
16
+ *
17
+ * Answers are a flat `Record<questionId, value>`. Each question declares an
18
+ * answer `type` that `validateAnswer` checks against — the same validation the
19
+ * UI runs before advancing and the store runs before persisting, so an invalid
20
+ * answer can never enter the payload.
21
+ */
22
+ /** The kinds of answer a question accepts. */
23
+ type IntakeAnswerType = 'text' | 'long-text' | 'single-select' | 'multi-select' | 'boolean' | 'number' | 'url' | 'email';
24
+ /** A selectable option for single/multi-select questions. */
25
+ interface IntakeOption {
26
+ value: string;
27
+ label: string;
28
+ }
29
+ /** A flat map of answers keyed by question id. */
30
+ type IntakeAnswers = Record<string, IntakeAnswerValue>;
31
+ /** Any value an answer can hold; the type is validated per-question. */
32
+ type IntakeAnswerValue = string | string[] | number | boolean | null;
33
+ /**
34
+ * One question in the graph. `next` (optional) makes the graph branch: given
35
+ * the answers so far it returns the id of the question to ask next, or null to
36
+ * end the interview early. With no `next`, traversal falls through to the next
37
+ * question in declaration order.
38
+ */
39
+ interface IntakeQuestion {
40
+ id: string;
41
+ /** The prompt the interviewer asks. */
42
+ prompt: string;
43
+ type: IntakeAnswerType;
44
+ /** Required questions gate completion; optional ones may be skipped. */
45
+ required?: boolean;
46
+ /** Help text shown under the prompt. */
47
+ help?: string;
48
+ /** Options for single/multi-select questions. */
49
+ options?: IntakeOption[];
50
+ /** Min length (text) or min value (number); inclusive. */
51
+ min?: number;
52
+ /** Max length (text) or max value (number); inclusive. */
53
+ max?: number;
54
+ /**
55
+ * Branch override: given the answers so far, the id of the next question
56
+ * (or null to end early). Omit for linear flow (next in declaration order).
57
+ */
58
+ next?(answers: IntakeAnswers): string | null;
59
+ }
60
+ /** The intake definition: an ordered, addressable set of questions. */
61
+ interface IntakeGraph {
62
+ /** Stable id for the intake definition (e.g. 'user-onboarding-v1'). */
63
+ id: string;
64
+ /** Human title shown at the top of the interview. */
65
+ title: string;
66
+ /** Optional one-line description. */
67
+ description?: string;
68
+ /** Questions in declaration (default traversal) order. */
69
+ questions: IntakeQuestion[];
70
+ }
71
+ /** The reason an answer failed validation. */
72
+ type AnswerRejectionReason = 'required' | 'wrong-type' | 'too-short' | 'too-long' | 'too-small' | 'too-large' | 'not-an-option' | 'invalid-url' | 'invalid-email' | 'unknown-question';
73
+ interface AnswerValidationResult {
74
+ ok: boolean;
75
+ reason?: AnswerRejectionReason;
76
+ }
77
+ /** Look up a question by id, or null if the graph has none. */
78
+ declare function getQuestion(graph: IntakeGraph, questionId: string): IntakeQuestion | null;
79
+ /** True when an answer value is present (not null/undefined/empty). */
80
+ declare function hasAnswer(value: IntakeAnswerValue | undefined): boolean;
81
+ /**
82
+ * Validate one answer against its question. Pure: no I/O, no graph mutation.
83
+ * An empty value is rejected as `required` only when the question is required;
84
+ * an empty value for an optional question is OK (the user skipped it).
85
+ */
86
+ declare function validateAnswer(question: IntakeQuestion, value: IntakeAnswerValue | undefined): AnswerValidationResult;
87
+ /**
88
+ * The single question to ask next given the answers so far, or null when the
89
+ * interview is done. Walks the graph from the first question, following each
90
+ * question's `next` branch (or declaration order) and stopping at the first
91
+ * reachable question that has no valid answer yet. Deterministic and pure.
92
+ *
93
+ * A `next` that points at a missing id, or returns null, ends the walk — so a
94
+ * malformed graph terminates rather than looping. A visited-set guards against
95
+ * a cyclic `next`.
96
+ */
97
+ declare function nextQuestion(graph: IntakeGraph, answers: IntakeAnswers): IntakeQuestion | null;
98
+ /**
99
+ * True when every REQUIRED question reachable under the current answers has a
100
+ * valid answer. Pure: it replays the same traversal `nextQuestion` uses and is
101
+ * complete exactly when that traversal has no question left to ask.
102
+ */
103
+ declare function isComplete(graph: IntakeGraph, answers: IntakeAnswers): boolean;
104
+ /**
105
+ * Progress as answered-vs-total over the REACHABLE required questions under the
106
+ * current answers — what a progress bar renders. Optional questions don't count
107
+ * toward the denominator (they never block completion).
108
+ */
109
+ declare function intakeProgress(graph: IntakeGraph, answers: IntakeAnswers): {
110
+ answered: number;
111
+ total: number;
112
+ };
113
+ /** The questions reachable under the current answers, in traversal order. */
114
+ declare function reachableQuestions(graph: IntakeGraph, answers: IntakeAnswers): IntakeQuestion[];
115
+
116
+ export { type AnswerRejectionReason as A, type IntakeAnswerValue as I, type IntakeQuestion as a, type IntakeGraph as b, type IntakeAnswers as c, type AnswerValidationResult as d, type IntakeAnswerType as e, type IntakeOption as f, getQuestion as g, hasAnswer as h, intakeProgress as i, isComplete as j, nextQuestion as n, reachableQuestions as r, validateAnswer as v };
@@ -4,7 +4,7 @@ import {
4
4
  lightTheme,
5
5
  themeColor,
6
6
  themeToCssVars
7
- } from "../chunk-Y2SZVW35.js";
7
+ } from "../chunk-LVD37K5V.js";
8
8
  export {
9
9
  darkTheme,
10
10
  lightTheme,
@@ -18,36 +18,36 @@
18
18
  */
19
19
 
20
20
  :root {
21
- /* shadcn channel triples — "H S% L%", consumed as hsl(var(--name)) */
21
+ /* shadcn channel triples — "H S% L%", consumed as hsl(var(--name)).
22
+ Values mirror @tangle-network/brand (Tangle Quiet) so agent-app surfaces
23
+ match sandbox-ui in the same app. agent-app keeps its own light-default /
24
+ [data-theme="dark"] scope model (brand is dark-default), so /theme stays
25
+ dependency-free — only the values are shared, not the cascade. */
22
26
  --background: 0 0% 100%;
23
- --foreground: 222 47% 11%;
24
- --card: 0 0% 100%;
25
- --card-foreground: 222 47% 11%;
27
+ --foreground: 0 0% 5%;
28
+ --card: 240 7% 97%;
29
+ --card-foreground: 0 0% 5%;
26
30
  --popover: 0 0% 100%;
27
- --popover-foreground: 222 47% 11%;
28
- --primary: 221 83% 47%;
31
+ --popover-foreground: 0 0% 5%;
32
+ --primary: 245 62% 57%;
29
33
  --primary-foreground: 0 0% 100%;
30
- --secondary: 210 40% 96%;
31
- --secondary-foreground: 222 47% 30%;
32
- --muted: 210 40% 96%;
33
- /* 44% L (was 47%) so muted text clears WCAG AA even on subtly tinted surfaces
34
- (e.g. the failed tool card's 5%-red wash); ~4.7:1 on white. */
35
- --muted-foreground: 215 16% 44%;
36
- --accent: 210 40% 96%;
37
- --accent-foreground: 222 47% 11%;
38
- --destructive: 0 72% 45%;
34
+ --secondary: 240 6% 93%;
35
+ --secondary-foreground: 0 0% 10%;
36
+ --muted: 240 6% 93%;
37
+ --muted-foreground: 240 5% 38%;
38
+ --accent: 240 6% 93%;
39
+ --accent-foreground: 0 0% 10%;
40
+ --destructive: 0 72% 41%;
39
41
  --destructive-foreground: 0 0% 100%;
40
- --border: 214 32% 91%;
41
- --input: 214 32% 91%;
42
- --ring: 221 83% 53%;
43
- /* note: --primary below is darkened from 53% 47% L so the brand blue clears
44
- WCAG AA (4.5:1) when used AS TEXT on a light surface; --ring stays at the
45
- brighter 53% (a 2px focus ring only needs 3:1 non-text contrast). */
46
- /* status colors — dark enough on light surfaces to clear AA as text (used by
47
- chips, dots, and solid buttons via the Tailwind preset's success/warning). */
48
- --success: 142 72% 29%;
42
+ --border: 240 6% 89%;
43
+ --input: 240 6% 89%;
44
+ --ring: 245 62% 57%;
45
+ /* status colors brand hues (teal/gold/red), but lightness kept dark enough
46
+ to clear WCAG AA when used AS TEXT on tinted chips. Brand's own status
47
+ accents are dot/surface colors and are not text-contrast-tuned. */
48
+ --success: 160 84% 26%;
49
49
  --success-foreground: 0 0% 100%;
50
- --warning: 38 92% 32%;
50
+ --warning: 41 96% 38%;
51
51
  --warning-foreground: 38 92% 12%;
52
52
 
53
53
  /* canvas/sequences aliases — full colors, resolve to the triples above */
@@ -62,34 +62,36 @@
62
62
 
63
63
  /* canvas-only surfaces (not part of the shadcn vocabulary). Name matches the
64
64
  `--canvas-backdrop` the design-canvas Workspace references (with a #1a1a1a fallback). */
65
- --canvas-backdrop: hsl(220 13% 91%);
65
+ --canvas-backdrop: hsl(240 7% 90%);
66
66
  }
67
67
 
68
68
  [data-theme='dark'],
69
69
  .dark {
70
- --background: 222 47% 7%;
71
- --foreground: 210 40% 98%;
72
- --card: 222 47% 11%;
73
- --card-foreground: 210 40% 98%;
74
- --popover: 222 47% 11%;
75
- --popover-foreground: 210 40% 98%;
76
- --primary: 217 91% 72%;
77
- --primary-foreground: 222 47% 11%;
78
- --secondary: 217 33% 17%;
79
- --secondary-foreground: 210 40% 90%;
80
- --muted: 217 33% 17%;
81
- --muted-foreground: 215 20% 65%;
82
- --accent: 217 33% 17%;
83
- --accent-foreground: 210 40% 98%;
84
- --destructive: 0 78% 67%;
70
+ --background: 240 8% 5%;
71
+ --foreground: 240 6% 93%;
72
+ --card: 240 5% 8%;
73
+ --card-foreground: 240 6% 93%;
74
+ --popover: 240 4% 13%;
75
+ --popover-foreground: 240 6% 93%;
76
+ /* 74% L (brand's #818CF8 intent) so primary clears AA as TEXT on a primary/10
77
+ tint in dark; the solid primary button pairs it with a light foreground. */
78
+ --primary: 239 84% 74%;
79
+ --primary-foreground: 0 0% 100%;
80
+ --secondary: 240 5% 11%;
81
+ --secondary-foreground: 240 6% 93%;
82
+ --muted: 240 5% 11%;
83
+ --muted-foreground: 240 4% 62%;
84
+ --accent: 240 5% 11%;
85
+ --accent-foreground: 240 6% 93%;
86
+ --destructive: 348 90% 68%;
85
87
  --destructive-foreground: 0 0% 12%;
86
- --border: 217 33% 20%;
87
- --input: 217 33% 20%;
88
- --ring: 217 91% 60%;
89
- --success: 142 60% 50%;
90
- --success-foreground: 142 80% 12%;
91
- --warning: 38 95% 58%;
88
+ --border: 240 3% 13%;
89
+ --input: 240 5% 11%;
90
+ --ring: 239 84% 74%;
91
+ --success: 160 70% 52%;
92
+ --success-foreground: 160 84% 10%;
93
+ --warning: 40 94% 56%;
92
94
  --warning-foreground: 38 92% 12%;
93
95
 
94
- --canvas-backdrop: hsl(0 0% 10%);
96
+ --canvas-backdrop: hsl(240 8% 5%);
95
97
  }
@@ -260,13 +260,18 @@ interface SeatPaywallProps {
260
260
  tagline?: string;
261
261
  /** CTA label. Default "Unlock {product}". */
262
262
  ctaLabel?: string;
263
+ /** Value-prop bullets. Default = product/usage-derived only; pass your own to
264
+ * supply product-specific value props (the shell bakes no GTM copy). */
265
+ benefits?: ReactNode[];
266
+ /** Optional fine print under the CTA (e.g. "Cancel anytime."). Omitted by default. */
267
+ footnote?: ReactNode;
263
268
  }
264
269
  /**
265
270
  * Centered card paywall. The price line reads
266
271
  * "$100/mo · includes $50/mo of AI usage" so the included allowance anchors the
267
272
  * value without ever exposing the ratio.
268
273
  */
269
- declare function SeatPaywall({ product, onCheckout, priceUsd, includedUsageUsd, tagline, ctaLabel, }: SeatPaywallProps): ReactNode;
274
+ declare function SeatPaywall({ product, onCheckout, priceUsd, includedUsageUsd, tagline, ctaLabel, benefits, footnote, }: SeatPaywallProps): ReactNode;
270
275
 
271
276
  /**
272
277
  * Keyboard + pointer model for a trigger-and-popover pair, dependency-free.
@@ -895,7 +895,9 @@ function SeatPaywall({
895
895
  priceUsd = 100,
896
896
  includedUsageUsd = 50,
897
897
  tagline,
898
- ctaLabel
898
+ ctaLabel,
899
+ benefits,
900
+ footnote
899
901
  }) {
900
902
  const { pending, run } = usePending();
901
903
  return /* @__PURE__ */ jsx4("div", { className: "flex min-h-[60vh] w-full items-center justify-center p-6", children: /* @__PURE__ */ jsxs4("div", { className: "w-full max-w-md rounded-2xl border border-border bg-card p-8 shadow-sm", children: [
@@ -917,18 +919,10 @@ function SeatPaywall({
917
919
  includedUsageUsd,
918
920
  "/mo of AI usage"
919
921
  ] }),
920
- /* @__PURE__ */ jsxs4("ul", { className: "mt-6 space-y-2.5", children: [
921
- /* @__PURE__ */ jsxs4(Benefit, { children: [
922
- "Full access to ",
923
- product
924
- ] }),
925
- /* @__PURE__ */ jsxs4(Benefit, { children: [
926
- "$",
927
- includedUsageUsd,
928
- "/mo of AI usage included, every month"
929
- ] }),
930
- /* @__PURE__ */ jsx4(Benefit, { children: "One Tangle wallet across every product you run" })
931
- ] }),
922
+ /* @__PURE__ */ jsx4("ul", { className: "mt-6 space-y-2.5", children: (benefits ?? [
923
+ `Full access to ${product}`,
924
+ `$${includedUsageUsd}/mo of AI usage included, every month`
925
+ ]).map((benefit, i) => /* @__PURE__ */ jsx4(Benefit, { children: benefit }, i)) }),
932
926
  /* @__PURE__ */ jsx4(
933
927
  "button",
934
928
  {
@@ -939,7 +933,7 @@ function SeatPaywall({
939
933
  children: pending ? "Opening checkout\u2026" : ctaLabel ?? `Unlock ${product}`
940
934
  }
941
935
  ),
942
- /* @__PURE__ */ jsx4("p", { className: "mt-3 text-center text-xs text-muted-foreground/70", children: "Cancel anytime." })
936
+ footnote && /* @__PURE__ */ jsx4("p", { className: "mt-3 text-center text-xs text-muted-foreground/70", children: footnote })
943
937
  ] }) });
944
938
  }
945
939