@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.
- package/dist/{DesignCanvasEditor-IB2FMBBD.js → DesignCanvasEditor-QQNAZRJQ.js} +3 -3
- package/dist/IntakeInterview-WHVKMNQW.js +8 -0
- package/dist/IntakeInterview-WHVKMNQW.js.map +1 -0
- package/dist/chunk-4K7BZYO7.js +124 -0
- package/dist/chunk-4K7BZYO7.js.map +1 -0
- package/dist/chunk-5I72FRZY.js +212 -0
- package/dist/chunk-5I72FRZY.js.map +1 -0
- package/dist/{chunk-S5CAJX6O.js → chunk-FJUOBNIY.js} +2 -2
- package/dist/{chunk-Y2SZVW35.js → chunk-LVD37K5V.js} +41 -41
- package/dist/chunk-LVD37K5V.js.map +1 -0
- package/dist/chunk-ND3XEGBE.js +119 -0
- package/dist/chunk-ND3XEGBE.js.map +1 -0
- package/dist/chunk-USYXHDKE.js +30 -0
- package/dist/chunk-USYXHDKE.js.map +1 -0
- package/dist/{chunk-N4ZFKQ5C.js → chunk-YYYXGLLQ.js} +2 -2
- package/dist/design-canvas-react/index.js +3 -3
- package/dist/design-canvas-react/lazy.js +1 -1
- package/dist/index.js +1 -1
- package/dist/intakes/api.d.ts +59 -0
- package/dist/intakes/api.js +63 -0
- package/dist/intakes/api.js.map +1 -0
- package/dist/intakes/drizzle.d.ts +385 -0
- package/dist/intakes/drizzle.js +61 -0
- package/dist/intakes/drizzle.js.map +1 -0
- package/dist/intakes/index.d.ts +42 -0
- package/dist/intakes/index.js +31 -0
- package/dist/intakes/index.js.map +1 -0
- package/dist/intakes-react/index.d.ts +48 -0
- package/dist/intakes-react/index.js +8 -0
- package/dist/intakes-react/index.js.map +1 -0
- package/dist/intakes-react/lazy.d.ts +8 -0
- package/dist/intakes-react/lazy.js +9 -0
- package/dist/intakes-react/lazy.js.map +1 -0
- package/dist/model-Cuj7d-xT.d.ts +116 -0
- package/dist/theme/index.js +1 -1
- package/dist/theme/tokens.css +50 -48
- package/dist/web-react/index.d.ts +6 -1
- package/dist/web-react/index.js +8 -14
- package/dist/web-react/index.js.map +1 -1
- package/package.json +26 -1
- package/dist/chunk-Y2SZVW35.js.map +0 -1
- /package/dist/{DesignCanvasEditor-IB2FMBBD.js.map → DesignCanvasEditor-QQNAZRJQ.js.map} +0 -0
- /package/dist/{chunk-S5CAJX6O.js.map → chunk-FJUOBNIY.js.map} +0 -0
- /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 };
|
package/dist/theme/index.js
CHANGED
package/dist/theme/tokens.css
CHANGED
|
@@ -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:
|
|
24
|
-
--card:
|
|
25
|
-
--card-foreground:
|
|
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:
|
|
28
|
-
--primary:
|
|
31
|
+
--popover-foreground: 0 0% 5%;
|
|
32
|
+
--primary: 245 62% 57%;
|
|
29
33
|
--primary-foreground: 0 0% 100%;
|
|
30
|
-
--secondary:
|
|
31
|
-
--secondary-foreground:
|
|
32
|
-
--muted:
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
--
|
|
36
|
-
--
|
|
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:
|
|
41
|
-
--input:
|
|
42
|
-
--ring:
|
|
43
|
-
/*
|
|
44
|
-
WCAG AA
|
|
45
|
-
|
|
46
|
-
|
|
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:
|
|
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(
|
|
65
|
+
--canvas-backdrop: hsl(240 7% 90%);
|
|
66
66
|
}
|
|
67
67
|
|
|
68
68
|
[data-theme='dark'],
|
|
69
69
|
.dark {
|
|
70
|
-
--background:
|
|
71
|
-
--foreground:
|
|
72
|
-
--card:
|
|
73
|
-
--card-foreground:
|
|
74
|
-
--popover:
|
|
75
|
-
--popover-foreground:
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
--
|
|
79
|
-
--
|
|
80
|
-
--
|
|
81
|
-
--
|
|
82
|
-
--
|
|
83
|
-
--
|
|
84
|
-
--
|
|
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:
|
|
87
|
-
--input:
|
|
88
|
-
--ring:
|
|
89
|
-
--success:
|
|
90
|
-
--success-foreground:
|
|
91
|
-
--warning:
|
|
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(
|
|
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.
|
package/dist/web-react/index.js
CHANGED
|
@@ -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__ */
|
|
921
|
-
|
|
922
|
-
|
|
923
|
-
|
|
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:
|
|
936
|
+
footnote && /* @__PURE__ */ jsx4("p", { className: "mt-3 text-center text-xs text-muted-foreground/70", children: footnote })
|
|
943
937
|
] }) });
|
|
944
938
|
}
|
|
945
939
|
|