setup-agent 0.0.9 → 0.1.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (49) hide show
  1. package/README.md +31 -0
  2. package/dist/browser.d.ts +40 -0
  3. package/dist/browser.d.ts.map +1 -0
  4. package/dist/browser.js +91 -0
  5. package/dist/browser.js.map +1 -0
  6. package/dist/cli.d.ts +23 -39
  7. package/dist/cli.d.ts.map +1 -1
  8. package/dist/cli.js +77 -125
  9. package/dist/cli.js.map +1 -1
  10. package/dist/host.d.ts.map +1 -1
  11. package/dist/host.js +13 -0
  12. package/dist/host.js.map +1 -1
  13. package/dist/index.d.ts +1 -1
  14. package/dist/index.d.ts.map +1 -1
  15. package/dist/index.js +2 -2
  16. package/dist/needs.d.ts +62 -0
  17. package/dist/needs.d.ts.map +1 -0
  18. package/dist/needs.js +184 -0
  19. package/dist/needs.js.map +1 -0
  20. package/dist/presets.js +1 -1
  21. package/dist/presets.js.map +1 -1
  22. package/dist/protocol.d.ts +16 -0
  23. package/dist/protocol.d.ts.map +1 -1
  24. package/dist/protocol.js +8 -1
  25. package/dist/protocol.js.map +1 -1
  26. package/dist/sdk.d.ts +48 -0
  27. package/dist/sdk.d.ts.map +1 -0
  28. package/dist/sdk.js +97 -0
  29. package/dist/sdk.js.map +1 -0
  30. package/dist/stream.d.ts +93 -0
  31. package/dist/stream.d.ts.map +1 -0
  32. package/dist/stream.js +184 -0
  33. package/dist/stream.js.map +1 -0
  34. package/package.json +5 -1
  35. package/src/browser.test.ts +192 -0
  36. package/src/browser.ts +146 -0
  37. package/src/cli.test.ts +57 -1
  38. package/src/cli.ts +134 -186
  39. package/src/host.test.ts +25 -0
  40. package/src/host.ts +7 -0
  41. package/src/index.ts +1 -0
  42. package/src/needs.test.ts +180 -0
  43. package/src/needs.ts +273 -0
  44. package/src/presets.ts +1 -1
  45. package/src/protocol.ts +17 -0
  46. package/src/sdk.test.ts +111 -0
  47. package/src/sdk.ts +145 -0
  48. package/src/stream.test.ts +223 -0
  49. package/src/stream.ts +314 -0
package/dist/needs.js ADDED
@@ -0,0 +1,184 @@
1
+ import { classifyChoiceAnswer, currentPlan, finishProposed, isClosed, isValidEntryPointAnswer, isValidModelAnswer, openInputs, parseModelAnswer, parseMultipleAnswer } from "./protocol.js";
2
+ // src/needs.ts
3
+ /** What the setup waits on the user for right now, oldest first. */
4
+ const pendingNeeds = (state) => {
5
+ if (state.createdAt === null || isClosed(state)) return [];
6
+ const needs = openInputs(state).map((input) => ({
7
+ id: input.id,
8
+ kind: "input",
9
+ input
10
+ }));
11
+ const plan = currentPlan(state);
12
+ if (plan?.status === "proposed") needs.push({
13
+ id: "plan",
14
+ kind: "plan",
15
+ plan
16
+ });
17
+ if (finishProposed(state) && !state.log.some((entry) => entry.role === "user" && entry.at > state.completion.proposedAt)) needs.push({
18
+ id: "finish",
19
+ kind: "finish",
20
+ completion: state.completion
21
+ });
22
+ return needs;
23
+ };
24
+ /** Tells one need from a later one with the same id, such as a new plan revision. */
25
+ const needKey = (need) => need.kind === "input" ? `input:${need.input.id}:${need.input.createdAt}` : need.kind === "plan" ? `plan:${need.plan.revision}:${need.plan.submittedAt}` : `finish:${need.completion.proposedAt}`;
26
+ /** Options as the ids an answer names: `<option>:<variant>` for an option with variants. */
27
+ const optionList = (input) => (input.options ?? []).flatMap((option) => {
28
+ const where = option.entryPoint ? ` (${option.entryPoint.formFactor}; ${option.entryPoint.placement}; ${option.entryPoint.trigger})` : "";
29
+ const description = `${option.description ?? ""}${where}`.trim();
30
+ const entry = (id, label) => ({
31
+ id,
32
+ label,
33
+ ...description && { description }
34
+ });
35
+ return option.variants?.length ? option.variants.map((variant) => entry(`${option.id}:${variant.id}`, `${option.label} (${variant.label})`)) : [entry(option.id, option.label)];
36
+ });
37
+ const ANSWER_FORMATS = {
38
+ text: "the user's text, as one shell word",
39
+ product: "add or decline",
40
+ model: "<provider>:<model>, such as openai:gpt-5",
41
+ "entry-point": "one option id",
42
+ choice: "one option id, or the user's own text"
43
+ };
44
+ const terminalQuestion = (need) => {
45
+ if (need.kind === "plan") return {
46
+ question: "Approve the setup plan? Show the user the plan you proposed and ask whether to go ahead or what to change.",
47
+ options: [{
48
+ id: "approve",
49
+ label: "Approve the plan"
50
+ }, {
51
+ id: "revise",
52
+ label: "Ask for changes (pass --feedback)"
53
+ }],
54
+ answerFormat: "approve, or revise --feedback \"<what to change>\""
55
+ };
56
+ if (need.kind === "finish") return {
57
+ question: `Everything is installed${need.completion.preview ? ` and running at ${need.completion.preview}` : ""}. Close the setup, or keep going?`,
58
+ options: [{
59
+ id: "close",
60
+ label: "Close the setup"
61
+ }],
62
+ answerFormat: "close; if the user wants more, do it and run done again instead"
63
+ };
64
+ const { input } = need;
65
+ const options = input.kind === "product" ? [{
66
+ id: "add",
67
+ label: `Add ${input.product ?? "the product"}`
68
+ }, {
69
+ id: "decline",
70
+ label: "Leave it out"
71
+ }] : input.kind === "text" ? void 0 : optionList(input);
72
+ return {
73
+ question: `${input.prompt.trim() || "Your agent needs an answer."}${input.optional ? " (optional; --dismiss skips it)" : ""}${input.kind === "model" ? " The API key is not typed here: the user adds it to the project's env file themselves." : ""}`,
74
+ ...options && { options },
75
+ ...input.multiple && { multiple: true },
76
+ answerFormat: input.multiple ? "option ids separated by commas, or the user's own text" : ANSWER_FORMATS[input.kind]
77
+ };
78
+ };
79
+ /** The question as one line: the prompt, then its options. */
80
+ const formatTerminalQuestion = ({ question, options, multiple }) => options ? `${question} Options${multiple ? ", any number" : ""}: ${options.map((option) => `${option.id} (${option.label}${option.description ? `: ${option.description}` : ""})`).join(", ")}.` : question;
81
+ const ids = (input) => optionList(input).map((option) => option.id).join(", ");
82
+ /** `value` as the wire answer `input` takes, or an error naming the shape it needs. */
83
+ const wireAnswer = (input, value) => {
84
+ const trimmed = value.trim();
85
+ if (input.kind === "model") {
86
+ const at = trimmed.indexOf(":");
87
+ const json = trimmed.startsWith("{") ? trimmed : JSON.stringify({
88
+ provider: trimmed.slice(0, at),
89
+ model: trimmed.slice(at + 1)
90
+ });
91
+ if (at <= 0 && !trimmed.startsWith("{")) throw new Error(`a model answer is "<provider>:<model>", such as openai:gpt-5`);
92
+ if (!isValidModelAnswer(input, json)) throw new Error(`a model answer names one of the providers: ${ids(input)}`);
93
+ return JSON.stringify(parseModelAnswer(json));
94
+ }
95
+ if (input.kind === "entry-point") {
96
+ if (!isValidEntryPointAnswer(input, trimmed)) throw new Error(`an entry-point answer is one of: ${ids(input)}`);
97
+ return trimmed;
98
+ }
99
+ if (input.kind === "choice") {
100
+ const answer = input.multiple && parseMultipleAnswer(trimmed) === void 0 ? JSON.stringify(trimmed.split(",").map((entry) => entry.trim()).filter(Boolean)) : trimmed;
101
+ if (classifyChoiceAnswer(input, answer) === "invalid") throw new Error(`"${value}" names an option without a valid variant; pick from: ${ids(input)}`);
102
+ return answer;
103
+ }
104
+ if (trimmed === "") throw new Error("an answer cannot be empty");
105
+ return value;
106
+ };
107
+ /**
108
+ * Answers a need from the agent's side, with what the user said in the
109
+ * agent's own conversation: an input, the plan (`approve` or `revise` with
110
+ * feedback) or the proposal to close (`close`).
111
+ */
112
+ const answerNeed = async (client, id, value, options = {}) => {
113
+ const state = client.state;
114
+ if (state === void 0) throw new Error("the setup has no state");
115
+ const { commands } = client;
116
+ if (id === "plan") {
117
+ const plan = currentPlan(state);
118
+ if (plan === void 0) throw new Error("no plan has been proposed");
119
+ const feedback = options.feedback?.trim();
120
+ if (value !== "approve" && (value !== "revise" || !feedback)) throw new Error("answer the plan with approve, or revise --feedback \"<what to change>\"");
121
+ await commands["checkout/plan"]({
122
+ ...state.id !== null && { id: state.id },
123
+ revision: plan.revision,
124
+ ...value === "approve" ? { decision: "approve" } : {
125
+ decision: "revise",
126
+ feedback
127
+ }
128
+ });
129
+ return {
130
+ ok: true,
131
+ id,
132
+ decision: value
133
+ };
134
+ }
135
+ if (id === "finish") {
136
+ if (!pendingNeeds(state).some((need) => need.id === "finish")) throw new Error("no proposal to close is waiting; finish the user's follow-up and run done again");
137
+ if (value !== "close") throw new Error("answer finish with close; if the user wants more, do it and run done again");
138
+ await commands["checkout/finish"]();
139
+ return {
140
+ ok: true,
141
+ id,
142
+ status: "done"
143
+ };
144
+ }
145
+ const input = state.inputs.find((candidate) => candidate.id === id);
146
+ if (input === void 0) throw new Error(`no input "${id}"`);
147
+ if (input.status !== "open") throw new Error(`input "${id}" is already ${input.status}`);
148
+ if (options.dismiss && !input.optional) throw new Error(`input "${id}" is required; answer it instead`);
149
+ if (options.dismiss || input.kind === "product" && value === "decline") {
150
+ await commands["checkout/dismiss"]({ inputId: id });
151
+ return {
152
+ ok: true,
153
+ id,
154
+ status: "dismissed"
155
+ };
156
+ }
157
+ if (value === void 0) throw new Error(`usage: answer ${id} <answer>`);
158
+ if (input.kind === "product") {
159
+ if (value !== "add") throw new Error("answer a product with add or decline");
160
+ const slug = input.product ?? "";
161
+ await commands["checkout/add-product"]({
162
+ inputId: id,
163
+ product: {
164
+ slug,
165
+ name: slug
166
+ }
167
+ });
168
+ } else {
169
+ const note = options.note?.trim();
170
+ await commands["checkout/answer"]({
171
+ inputId: id,
172
+ answer: wireAnswer(input, value),
173
+ ...note && { note }
174
+ });
175
+ }
176
+ return {
177
+ ok: true,
178
+ id,
179
+ status: "answered"
180
+ };
181
+ };
182
+ export { answerNeed, formatTerminalQuestion, needKey, pendingNeeds, terminalQuestion };
183
+
184
+ //# sourceMappingURL=needs.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"needs.js","names":[],"sources":["../src/needs.ts"],"sourcesContent":["import type { CheckoutClient } from \"./client\";\nimport {\n classifyChoiceAnswer,\n currentPlan,\n finishProposed,\n isClosed,\n isValidEntryPointAnswer,\n isValidModelAnswer,\n parseModelAnswer,\n openInputs,\n parseMultipleAnswer,\n} from \"./protocol\";\nimport type { Checkout } from \"./protocol\";\n\n/**\n * Something the setup waits on the user for: an open question, a proposed\n * plan, or the agent's proposal to close. `id` is what `answer` takes: the\n * input id, `plan` or `finish`.\n */\nexport type SetupNeed =\n | { id: string; kind: \"input\"; input: Checkout.Input }\n | { id: \"plan\"; kind: \"plan\"; plan: Checkout.Plan }\n | { id: \"finish\"; kind: \"finish\"; completion: Checkout.Completion };\n\n/** What the setup waits on the user for right now, oldest first. */\nexport const pendingNeeds = (state: Checkout.State): SetupNeed[] => {\n if (state.createdAt === null || isClosed(state)) return [];\n const needs: SetupNeed[] = openInputs(state).map((input) => ({\n id: input.id,\n kind: \"input\",\n input,\n }));\n const plan = currentPlan(state);\n if (plan?.status === \"proposed\")\n needs.push({ id: \"plan\", kind: \"plan\", plan });\n // Any message after the proposal, acknowledged or not, means more work first.\n if (\n finishProposed(state) &&\n !state.log.some(\n (entry) =>\n entry.role === \"user\" && entry.at > state.completion!.proposedAt,\n )\n )\n needs.push({ id: \"finish\", kind: \"finish\", completion: state.completion! });\n return needs;\n};\n\n/** Tells one need from a later one with the same id, such as a new plan revision. */\nexport const needKey = (need: SetupNeed) =>\n need.kind === \"input\"\n ? `input:${need.input.id}:${need.input.createdAt}`\n : need.kind === \"plan\"\n ? `plan:${need.plan.revision}:${need.plan.submittedAt}`\n : `finish:${need.completion.proposedAt}`;\n\ntype NeedOption = { id: string; label: string; description?: string };\n\n/** A need as a question the agent can put to the user in its own conversation. */\nexport type TerminalQuestion = {\n question: string;\n options?: NeedOption[];\n multiple?: true;\n /** The shape of the answer, as the `answer` command takes it. */\n answerFormat: string;\n};\n\n/** Options as the ids an answer names: `<option>:<variant>` for an option with variants. */\nconst optionList = (input: Checkout.Input): NeedOption[] =>\n (input.options ?? []).flatMap((option) => {\n const where = option.entryPoint\n ? ` (${option.entryPoint.formFactor}; ${option.entryPoint.placement}; ${option.entryPoint.trigger})`\n : \"\";\n const description = `${option.description ?? \"\"}${where}`.trim();\n const entry = (id: string, label: string) => ({\n id,\n label,\n ...(description && { description }),\n });\n return option.variants?.length\n ? option.variants.map((variant) =>\n entry(\n `${option.id}:${variant.id}`,\n `${option.label} (${variant.label})`,\n ),\n )\n : [entry(option.id, option.label)];\n });\n\nconst ANSWER_FORMATS: Record<Checkout.InputKind, string> = {\n text: \"the user's text, as one shell word\",\n product: \"add or decline\",\n model: \"<provider>:<model>, such as openai:gpt-5\",\n \"entry-point\": \"one option id\",\n choice: \"one option id, or the user's own text\",\n};\n\nexport const terminalQuestion = (need: SetupNeed): TerminalQuestion => {\n if (need.kind === \"plan\")\n return {\n question:\n \"Approve the setup plan? Show the user the plan you proposed and ask whether to go ahead or what to change.\",\n options: [\n { id: \"approve\", label: \"Approve the plan\" },\n { id: \"revise\", label: \"Ask for changes (pass --feedback)\" },\n ],\n answerFormat: 'approve, or revise --feedback \"<what to change>\"',\n };\n if (need.kind === \"finish\")\n return {\n question: `Everything is installed${need.completion.preview ? ` and running at ${need.completion.preview}` : \"\"}. Close the setup, or keep going?`,\n options: [{ id: \"close\", label: \"Close the setup\" }],\n answerFormat:\n \"close; if the user wants more, do it and run done again instead\",\n };\n const { input } = need;\n const options =\n input.kind === \"product\"\n ? [\n { id: \"add\", label: `Add ${input.product ?? \"the product\"}` },\n { id: \"decline\", label: \"Leave it out\" },\n ]\n : input.kind === \"text\"\n ? undefined\n : optionList(input);\n return {\n question: `${input.prompt.trim() || \"Your agent needs an answer.\"}${input.optional ? \" (optional; --dismiss skips it)\" : \"\"}${input.kind === \"model\" ? \" The API key is not typed here: the user adds it to the project's env file themselves.\" : \"\"}`,\n ...(options && { options }),\n ...(input.multiple && { multiple: true as const }),\n answerFormat: input.multiple\n ? \"option ids separated by commas, or the user's own text\"\n : ANSWER_FORMATS[input.kind],\n };\n};\n\n/** The question as one line: the prompt, then its options. */\nexport const formatTerminalQuestion = ({\n question,\n options,\n multiple,\n}: TerminalQuestion) =>\n options\n ? `${question} Options${multiple ? \", any number\" : \"\"}: ${options\n .map(\n (option) =>\n `${option.id} (${option.label}${option.description ? `: ${option.description}` : \"\"})`,\n )\n .join(\", \")}.`\n : question;\n\nconst ids = (input: Checkout.Input) =>\n optionList(input)\n .map((option) => option.id)\n .join(\", \");\n\n/** `value` as the wire answer `input` takes, or an error naming the shape it needs. */\nconst wireAnswer = (input: Checkout.Input, value: string) => {\n const trimmed = value.trim();\n if (input.kind === \"model\") {\n const at = trimmed.indexOf(\":\");\n const json = trimmed.startsWith(\"{\")\n ? trimmed\n : JSON.stringify({\n provider: trimmed.slice(0, at),\n model: trimmed.slice(at + 1),\n });\n if (at <= 0 && !trimmed.startsWith(\"{\"))\n throw new Error(\n `a model answer is \"<provider>:<model>\", such as openai:gpt-5`,\n );\n if (!isValidModelAnswer(input, json))\n throw new Error(\n `a model answer names one of the providers: ${ids(input)}`,\n );\n // Only the documented fields; anything else (a key, say) never reaches the setup.\n return JSON.stringify(parseModelAnswer(json));\n }\n if (input.kind === \"entry-point\") {\n if (!isValidEntryPointAnswer(input, trimmed))\n throw new Error(`an entry-point answer is one of: ${ids(input)}`);\n return trimmed;\n }\n if (input.kind === \"choice\") {\n const answer =\n input.multiple && parseMultipleAnswer(trimmed) === undefined\n ? JSON.stringify(\n trimmed\n .split(\",\")\n .map((entry) => entry.trim())\n .filter(Boolean),\n )\n : trimmed;\n if (classifyChoiceAnswer(input, answer) === \"invalid\")\n throw new Error(\n `\"${value}\" names an option without a valid variant; pick from: ${ids(input)}`,\n );\n return answer;\n }\n if (trimmed === \"\") throw new Error(\"an answer cannot be empty\");\n return value;\n};\n\n/**\n * Answers a need from the agent's side, with what the user said in the\n * agent's own conversation: an input, the plan (`approve` or `revise` with\n * feedback) or the proposal to close (`close`).\n */\nexport const answerNeed = async (\n client: Pick<CheckoutClient, \"state\" | \"commands\">,\n id: string,\n value: string | undefined,\n options: { note?: string; feedback?: string; dismiss?: boolean } = {},\n) => {\n const state = client.state;\n if (state === undefined) throw new Error(\"the setup has no state\");\n const { commands } = client;\n if (id === \"plan\") {\n const plan = currentPlan(state);\n if (plan === undefined) throw new Error(\"no plan has been proposed\");\n const feedback = options.feedback?.trim();\n if (value !== \"approve\" && (value !== \"revise\" || !feedback))\n throw new Error(\n 'answer the plan with approve, or revise --feedback \"<what to change>\"',\n );\n await commands[\"checkout/plan\"]({\n ...(state.id !== null && { id: state.id }),\n revision: plan.revision,\n ...(value === \"approve\"\n ? { decision: \"approve\" as const }\n : { decision: \"revise\" as const, feedback: feedback! }),\n });\n return { ok: true, id, decision: value };\n }\n if (id === \"finish\") {\n if (!pendingNeeds(state).some((need) => need.id === \"finish\"))\n throw new Error(\n \"no proposal to close is waiting; finish the user's follow-up and run done again\",\n );\n if (value !== \"close\")\n throw new Error(\n \"answer finish with close; if the user wants more, do it and run done again\",\n );\n await commands[\"checkout/finish\"]();\n return { ok: true, id, status: \"done\" };\n }\n const input = state.inputs.find((candidate) => candidate.id === id);\n if (input === undefined) throw new Error(`no input \"${id}\"`);\n if (input.status !== \"open\")\n throw new Error(`input \"${id}\" is already ${input.status}`);\n if (options.dismiss && !input.optional)\n throw new Error(`input \"${id}\" is required; answer it instead`);\n if (options.dismiss || (input.kind === \"product\" && value === \"decline\")) {\n await commands[\"checkout/dismiss\"]({ inputId: id });\n return { ok: true, id, status: \"dismissed\" };\n }\n if (value === undefined) throw new Error(`usage: answer ${id} <answer>`);\n if (input.kind === \"product\") {\n if (value !== \"add\")\n throw new Error(\"answer a product with add or decline\");\n const slug = input.product ?? \"\";\n await commands[\"checkout/add-product\"]({\n inputId: id,\n product: { slug, name: slug },\n });\n } else {\n const note = options.note?.trim();\n await commands[\"checkout/answer\"]({\n inputId: id,\n answer: wireAnswer(input, value),\n ...(note && { note }),\n });\n }\n return { ok: true, id, status: \"answered\" };\n};\n"],"mappings":"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"}
package/dist/presets.js CHANGED
@@ -135,7 +135,7 @@ const INPUT_PRESETS = {
135
135
  }],
136
136
  help: {
137
137
  summary: "Pick the app the assistant should live in. For a new project, Next.js is the shortest path: the assistant-ui CLI scaffolds the chat route with it. Pick Vite, React Router or TanStack Start when the rest of your stack already uses them, and Expo for a native app.",
138
- href: `${DOCS}/docs/installation`
138
+ href: `${DOCS}/docs/manual-installation`
139
139
  }
140
140
  }
141
141
  };
@@ -1 +1 @@
1
- {"version":3,"file":"presets.js","names":[],"sources":["../src/presets.ts"],"sourcesContent":["import type { Checkout } from \"./protocol\";\n\nconst TYPESCRIPT = { id: \"typescript\", label: \"TypeScript\" };\nconst PYTHON = { id: \"python\", label: \"Python\" };\n\nconst DOCS = \"https://www.assistant-ui.com\";\n\nexport type PresetId = \"framework\" | \"llm-provider\" | \"project\";\n\nexport type PresetOverrides = {\n /** Restrict the options to these ids, in this order; one id locks the choice in. */\n only?: readonly string[];\n /** Options the agent found itself, listed before the preset's own; `only` leaves them out. */\n found?: readonly { id: string; description?: string }[];\n default?: string;\n optional?: boolean;\n stepId?: string;\n};\n\ntype Preset = {\n kind: Checkout.InputKind;\n prompt: string;\n options: Checkout.ChoiceOption[];\n default?: string;\n help: Checkout.InputHelp;\n};\n\n/** The standard inputs an agent can ask with `ask --preset <id>`. */\nexport const INPUT_PRESETS: Record<PresetId, Preset> = {\n framework: {\n kind: \"choice\",\n prompt: \"Which agent framework runs your backend?\",\n options: [\n {\n id: \"ai-sdk\",\n label: \"Vercel AI SDK\",\n description: \"Shortest path for Next.js and React\",\n icon: \"vercel\",\n variants: [TYPESCRIPT],\n },\n {\n id: \"mastra\",\n label: \"Mastra\",\n description: \"Workflows, memory and tools\",\n icon: \"mastra\",\n variants: [TYPESCRIPT],\n },\n {\n id: \"langgraph\",\n label: \"LangGraph\",\n description: \"Stateful graphs, Python or TypeScript\",\n icon: \"langgraph\",\n variants: [PYTHON, TYPESCRIPT],\n },\n ],\n help: {\n summary:\n \"Already on one of these? Pick it. Starting fresh in Next.js, the AI SDK is the shortest path. Mastra adds workflows and memory in TypeScript. LangGraph fits a Python backend or multi-step graphs that pause for a human.\",\n href: `${DOCS}/docs/runtimes/pick-a-runtime`,\n },\n },\n \"llm-provider\": {\n kind: \"model\",\n prompt: \"Which model should the assistant use?\",\n options: [\n {\n id: \"openai\",\n label: \"OpenAI\",\n description: \"OPENAI_API_KEY\",\n icon: \"openai\",\n },\n {\n id: \"anthropic\",\n label: \"Anthropic\",\n description: \"ANTHROPIC_API_KEY\",\n icon: \"anthropic\",\n },\n {\n id: \"google\",\n label: \"Google Gemini\",\n description: \"GOOGLE_GENERATIVE_AI_API_KEY\",\n icon: \"google\",\n },\n {\n id: \"openrouter\",\n label: \"OpenRouter\",\n description: \"OPENROUTER_API_KEY\",\n icon: \"openrouter\",\n },\n { id: \"xai\", label: \"xAI\", description: \"XAI_API_KEY\", icon: \"xai\" },\n {\n id: \"mistral\",\n label: \"Mistral\",\n description: \"MISTRAL_API_KEY\",\n icon: \"mistral\",\n },\n {\n id: \"deepseek\",\n label: \"DeepSeek\",\n description: \"DEEPSEEK_API_KEY\",\n icon: \"deepseek\",\n },\n { id: \"groq\", label: \"Groq\", description: \"GROQ_API_KEY\", icon: \"groq\" },\n {\n id: \"fireworks\",\n label: \"Fireworks AI\",\n description: \"FIREWORKS_API_KEY\",\n icon: \"fireworks\",\n },\n ],\n default: \"openai\",\n help: {\n summary:\n \"Any of them works with every framework here. Pick the one whose API key you already have, or OpenRouter to reach many models with one key.\",\n },\n },\n project: {\n kind: \"choice\",\n prompt: \"Which project should this go into?\",\n options: [\n {\n id: \"new\",\n label: \"New project\",\n description: \"Start a fresh React app here\",\n variants: [\n { id: \"next\", label: \"Next.js\" },\n { id: \"vite\", label: \"Vite\" },\n { id: \"react-router\", label: \"React Router\" },\n { id: \"tanstack-start\", label: \"TanStack Start\" },\n { id: \"expo\", label: \"Expo\" },\n ],\n },\n ],\n help: {\n summary:\n \"Pick the app the assistant should live in. For a new project, Next.js is the shortest path: the assistant-ui CLI scaffolds the chat route with it. Pick Vite, React Router or TanStack Start when the rest of your stack already uses them, and Expo for a native app.\",\n href: `${DOCS}/docs/installation`,\n },\n },\n};\n\nexport const isPresetId = (id: string): id is PresetId =>\n Object.hasOwn(INPUT_PRESETS, id);\n\n/** Build the seed for a standard input, throwing on an unknown preset, option or default. */\nexport const presetInput = (\n id: PresetId,\n overrides: PresetOverrides = {},\n): Checkout.InputSeed & { stepId?: string } => {\n const preset = INPUT_PRESETS[id];\n const listed = overrides.only\n ? overrides.only.map((optionId) => {\n const option = preset.options.find((c) => c.id === optionId);\n if (!option)\n throw new Error(`preset \"${id}\" has no option \"${optionId}\"`);\n return option;\n })\n : preset.options;\n const found = (overrides.found ?? []).map((option) => {\n if (\n option.id.includes(\":\") ||\n preset.options.some((o) => o.id === option.id)\n ) {\n throw new Error(`preset \"${id}\" cannot list \"${option.id}\" as an option`);\n }\n return { ...option, label: option.id };\n });\n const options = overrides.only ? listed : [...found, ...listed];\n const fallback = options.some((o) => o.id === preset.default)\n ? preset.default\n : undefined;\n const chosen = overrides.default ?? fallback;\n if (chosen !== undefined && !options.some((o) => o.id === chosen)) {\n throw new Error(`preset \"${id}\" has no option \"${chosen}\" to default to`);\n }\n return {\n kind: preset.kind,\n preset: id,\n prompt: preset.prompt,\n options,\n ...(chosen !== undefined && { default: chosen }),\n help: preset.help,\n optional: overrides.optional ?? false,\n ...(overrides.stepId !== undefined && { stepId: overrides.stepId }),\n };\n};\n"],"mappings":"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"}
1
+ {"version":3,"file":"presets.js","names":[],"sources":["../src/presets.ts"],"sourcesContent":["import type { Checkout } from \"./protocol\";\n\nconst TYPESCRIPT = { id: \"typescript\", label: \"TypeScript\" };\nconst PYTHON = { id: \"python\", label: \"Python\" };\n\nconst DOCS = \"https://www.assistant-ui.com\";\n\nexport type PresetId = \"framework\" | \"llm-provider\" | \"project\";\n\nexport type PresetOverrides = {\n /** Restrict the options to these ids, in this order; one id locks the choice in. */\n only?: readonly string[];\n /** Options the agent found itself, listed before the preset's own; `only` leaves them out. */\n found?: readonly { id: string; description?: string }[];\n default?: string;\n optional?: boolean;\n stepId?: string;\n};\n\ntype Preset = {\n kind: Checkout.InputKind;\n prompt: string;\n options: Checkout.ChoiceOption[];\n default?: string;\n help: Checkout.InputHelp;\n};\n\n/** The standard inputs an agent can ask with `ask --preset <id>`. */\nexport const INPUT_PRESETS: Record<PresetId, Preset> = {\n framework: {\n kind: \"choice\",\n prompt: \"Which agent framework runs your backend?\",\n options: [\n {\n id: \"ai-sdk\",\n label: \"Vercel AI SDK\",\n description: \"Shortest path for Next.js and React\",\n icon: \"vercel\",\n variants: [TYPESCRIPT],\n },\n {\n id: \"mastra\",\n label: \"Mastra\",\n description: \"Workflows, memory and tools\",\n icon: \"mastra\",\n variants: [TYPESCRIPT],\n },\n {\n id: \"langgraph\",\n label: \"LangGraph\",\n description: \"Stateful graphs, Python or TypeScript\",\n icon: \"langgraph\",\n variants: [PYTHON, TYPESCRIPT],\n },\n ],\n help: {\n summary:\n \"Already on one of these? Pick it. Starting fresh in Next.js, the AI SDK is the shortest path. Mastra adds workflows and memory in TypeScript. LangGraph fits a Python backend or multi-step graphs that pause for a human.\",\n href: `${DOCS}/docs/runtimes/pick-a-runtime`,\n },\n },\n \"llm-provider\": {\n kind: \"model\",\n prompt: \"Which model should the assistant use?\",\n options: [\n {\n id: \"openai\",\n label: \"OpenAI\",\n description: \"OPENAI_API_KEY\",\n icon: \"openai\",\n },\n {\n id: \"anthropic\",\n label: \"Anthropic\",\n description: \"ANTHROPIC_API_KEY\",\n icon: \"anthropic\",\n },\n {\n id: \"google\",\n label: \"Google Gemini\",\n description: \"GOOGLE_GENERATIVE_AI_API_KEY\",\n icon: \"google\",\n },\n {\n id: \"openrouter\",\n label: \"OpenRouter\",\n description: \"OPENROUTER_API_KEY\",\n icon: \"openrouter\",\n },\n { id: \"xai\", label: \"xAI\", description: \"XAI_API_KEY\", icon: \"xai\" },\n {\n id: \"mistral\",\n label: \"Mistral\",\n description: \"MISTRAL_API_KEY\",\n icon: \"mistral\",\n },\n {\n id: \"deepseek\",\n label: \"DeepSeek\",\n description: \"DEEPSEEK_API_KEY\",\n icon: \"deepseek\",\n },\n { id: \"groq\", label: \"Groq\", description: \"GROQ_API_KEY\", icon: \"groq\" },\n {\n id: \"fireworks\",\n label: \"Fireworks AI\",\n description: \"FIREWORKS_API_KEY\",\n icon: \"fireworks\",\n },\n ],\n default: \"openai\",\n help: {\n summary:\n \"Any of them works with every framework here. Pick the one whose API key you already have, or OpenRouter to reach many models with one key.\",\n },\n },\n project: {\n kind: \"choice\",\n prompt: \"Which project should this go into?\",\n options: [\n {\n id: \"new\",\n label: \"New project\",\n description: \"Start a fresh React app here\",\n variants: [\n { id: \"next\", label: \"Next.js\" },\n { id: \"vite\", label: \"Vite\" },\n { id: \"react-router\", label: \"React Router\" },\n { id: \"tanstack-start\", label: \"TanStack Start\" },\n { id: \"expo\", label: \"Expo\" },\n ],\n },\n ],\n help: {\n summary:\n \"Pick the app the assistant should live in. For a new project, Next.js is the shortest path: the assistant-ui CLI scaffolds the chat route with it. Pick Vite, React Router or TanStack Start when the rest of your stack already uses them, and Expo for a native app.\",\n href: `${DOCS}/docs/manual-installation`,\n },\n },\n};\n\nexport const isPresetId = (id: string): id is PresetId =>\n Object.hasOwn(INPUT_PRESETS, id);\n\n/** Build the seed for a standard input, throwing on an unknown preset, option or default. */\nexport const presetInput = (\n id: PresetId,\n overrides: PresetOverrides = {},\n): Checkout.InputSeed & { stepId?: string } => {\n const preset = INPUT_PRESETS[id];\n const listed = overrides.only\n ? overrides.only.map((optionId) => {\n const option = preset.options.find((c) => c.id === optionId);\n if (!option)\n throw new Error(`preset \"${id}\" has no option \"${optionId}\"`);\n return option;\n })\n : preset.options;\n const found = (overrides.found ?? []).map((option) => {\n if (\n option.id.includes(\":\") ||\n preset.options.some((o) => o.id === option.id)\n ) {\n throw new Error(`preset \"${id}\" cannot list \"${option.id}\" as an option`);\n }\n return { ...option, label: option.id };\n });\n const options = overrides.only ? listed : [...found, ...listed];\n const fallback = options.some((o) => o.id === preset.default)\n ? preset.default\n : undefined;\n const chosen = overrides.default ?? fallback;\n if (chosen !== undefined && !options.some((o) => o.id === chosen)) {\n throw new Error(`preset \"${id}\" has no option \"${chosen}\" to default to`);\n }\n return {\n kind: preset.kind,\n preset: id,\n prompt: preset.prompt,\n options,\n ...(chosen !== undefined && { default: chosen }),\n help: preset.help,\n optional: overrides.optional ?? false,\n ...(overrides.stepId !== undefined && { stepId: overrides.stepId }),\n };\n};\n"],"mappings":"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"}
@@ -151,6 +151,15 @@ export declare namespace Checkout {
151
151
  /** When the command was first run against this checkout, before the agent joined the stream. */
152
152
  introducedAt: number | null;
153
153
  };
154
+ /**
155
+ * The setup page in the user's browser, while one has joined the link.
156
+ * Absent on hosts older than browser presence.
157
+ */
158
+ browser?: {
159
+ lastSeenAt: number | null;
160
+ /** False once the page said goodbye; heartbeats set it again. */
161
+ connected: boolean;
162
+ };
154
163
  /** Every revision in order; the last one is current. */
155
164
  plans: Plan[];
156
165
  steps: Step[];
@@ -226,6 +235,10 @@ export declare namespace Checkout {
226
235
  }) => void;
227
236
  "agent/heartbeat": () => void;
228
237
  "agent/bye": () => void;
238
+ /** The setup page is open and joined; sent every BROWSER_HEARTBEAT_MS. */
239
+ "browser/heartbeat": () => void;
240
+ /** The setup page is closing. */
241
+ "browser/bye": () => void;
229
242
  "agent/plan": (params: {
230
243
  markdown: string;
231
244
  }) => {
@@ -262,6 +275,9 @@ export declare namespace Checkout {
262
275
  }
263
276
  export declare const AGENT_PRESENCE_MS = 15000;
264
277
  export declare const AGENT_HEARTBEAT_MS = 5000;
278
+ /** A background tab's timers slow down, so a browser counts as present for longer than an agent. */
279
+ export declare const BROWSER_PRESENCE_MS = 20000;
280
+ export declare const BROWSER_HEARTBEAT_MS = 5000;
265
281
  export declare const initialCheckoutState: () => Checkout.State;
266
282
  export declare const isAgentPresent: (state: Checkout.State, now?: number) => boolean;
267
283
  export declare const isClosed: (state: Checkout.State) => boolean;
@@ -1 +1 @@
1
- {"version":3,"file":"protocol.d.ts","sourceRoot":"","sources":["../src/protocol.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"protocol.d.ts","sourceRoot":"","sources":["../src/protocol.ts"],"names":[],"mappings":"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"}
package/dist/protocol.js CHANGED
@@ -1,6 +1,9 @@
1
1
  // src/protocol.ts
2
2
  const AGENT_PRESENCE_MS = 15e3;
3
3
  const AGENT_HEARTBEAT_MS = 5e3;
4
+ /** A background tab's timers slow down, so a browser counts as present for longer than an agent. */
5
+ const BROWSER_PRESENCE_MS = 2e4;
6
+ const BROWSER_HEARTBEAT_MS = 5e3;
4
7
  const initialCheckoutState = () => ({
5
8
  version: 2,
6
9
  id: null,
@@ -15,6 +18,10 @@ const initialCheckoutState = () => ({
15
18
  kind: null,
16
19
  introducedAt: null
17
20
  },
21
+ browser: {
22
+ lastSeenAt: null,
23
+ connected: false
24
+ },
18
25
  plans: [],
19
26
  steps: [],
20
27
  inputs: [],
@@ -211,6 +218,6 @@ const stepProgress = (state) => ({
211
218
  total: state.steps.length,
212
219
  done: state.steps.filter((step) => step.status === "done" || step.status === "skipped").length
213
220
  });
214
- export { AGENT_HEARTBEAT_MS, AGENT_PRESENCE_MS, OPTION_ICONS, classifyChoiceAnswer, currentPlan, finishProposed, followedUpSinceProposal, initialCheckoutState, isAgentPresent, isClosed, isLoopbackHostname, isOptionIcon, isValidEntryPointAnswer, isValidEntryPointInput, isValidModelAnswer, openInputs, parseChoiceAnswer, parseEntryPointOptions, parseModelAnswer, parseMultipleAnswer, parsePreviewUrl, planNeedsReview, stepProgress };
221
+ export { AGENT_HEARTBEAT_MS, AGENT_PRESENCE_MS, BROWSER_HEARTBEAT_MS, BROWSER_PRESENCE_MS, OPTION_ICONS, classifyChoiceAnswer, currentPlan, finishProposed, followedUpSinceProposal, initialCheckoutState, isAgentPresent, isClosed, isLoopbackHostname, isOptionIcon, isValidEntryPointAnswer, isValidEntryPointInput, isValidModelAnswer, openInputs, parseChoiceAnswer, parseEntryPointOptions, parseModelAnswer, parseMultipleAnswer, parsePreviewUrl, planNeedsReview, stepProgress };
215
222
 
216
223
  //# sourceMappingURL=protocol.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"protocol.js","names":[],"sources":["../src/protocol.ts"],"sourcesContent":["export namespace Checkout {\n export type StepStatus =\n | \"pending\"\n | \"active\"\n | \"done\"\n | \"skipped\"\n | \"blocked\";\n\n /** A unit of install work the agent declared; the catalog seeds none. */\n export type Step = {\n id: string;\n title: string;\n detail?: string;\n status: StepStatus;\n note?: string;\n /** The product this step belongs to, when the agent said. */\n product?: string;\n createdAt: number;\n };\n\n export type Product = {\n slug: string;\n name: string;\n /** The install reference the agent fetches while planning. */\n guide?: string;\n };\n\n export type InputStatus = \"open\" | \"answered\" | \"dismissed\";\n\n /**\n * product: the agent proposes adding a product to this checkout, such as one\n * another product depends on. The browser owns the catalog, so it answers\n * with `checkout/add-product`; dismissing the input declines.\n */\n export type InputKind =\n | \"text\"\n | \"choice\"\n | \"model\"\n | \"product\"\n | \"entry-point\";\n\n export type EntryPoint = {\n formFactor: \"modal\" | \"sidebar\" | \"full-page\";\n placement: string;\n trigger: string;\n recommended?: boolean;\n };\n\n export type EntryPointOption = {\n id: string;\n label: string;\n description: string;\n entryPoint: EntryPoint;\n };\n\n export type ChoiceVariant = { id: string; label: string };\n\n export type ChoiceOption = {\n id: string;\n label: string;\n description?: string;\n /** A name from OPTION_ICONS, or the key of a brand mark on a preset option; unknown keys render without one. */\n icon?: string;\n /** A second pick under this option, such as the language of a framework. */\n variants?: ChoiceVariant[];\n entryPoint?: EntryPoint;\n };\n\n /** A short nudge for users who need help choosing, with a longer guide to link to. */\n export type InputHelp = { summary: string; href?: string };\n\n /**\n * The answer to a model input, stored as JSON text. The API key itself is\n * never part of it: the browser deposits it with the checkout and the\n * agent's `env` command writes it straight to a file.\n */\n export type ModelAnswer = {\n provider: string;\n model: string;\n reasoningEffort?: \"low\" | \"medium\" | \"high\";\n };\n\n /**\n * A choice answer is an option id, `<option>:<variant>` when the option has\n * variants, or the user's own text when none of the options fit; a multiple\n * choice answers a JSON array of those. A model answer is a JSON-encoded\n * ModelAnswer whose provider is one of the options.\n */\n export type Input = {\n phase: Status;\n id: string;\n kind: InputKind;\n /** The standard input this was built from, when it was. */\n preset?: string;\n prompt: string;\n placeholder?: string;\n options?: ChoiceOption[];\n /** The user may pick any number of options; the answer is a JSON array. */\n multiple?: true;\n /** The slug a product input proposes. */\n product?: string;\n default?: string;\n help?: InputHelp;\n redeemKeyHash?: string;\n optional: boolean;\n status: InputStatus;\n answer?: string;\n /** A remark the user attached to the answer. */\n note?: string;\n stepId?: string;\n createdAt: number;\n answeredAt?: number;\n };\n\n export type LogEntry = {\n phase: Status;\n id: string;\n role: \"agent\" | \"user\";\n acknowledgedAt?: number;\n at: number;\n text: string;\n /** The step that was active when the line was posted; none while planning. */\n stepId?: string;\n };\n\n export type PlanStatus = \"proposed\" | \"approved\" | \"changes-requested\";\n\n /** One revision of the agent's plan. Markdown the browser renders. */\n export type Plan = {\n revision: number;\n markdown: string;\n status: PlanStatus;\n submittedAt: number;\n decidedAt?: number;\n /** What the user asked to change, when they did. */\n feedback?: string;\n };\n\n /**\n * waiting: no agent has joined. planning: the agent investigates and\n * proposes a plan. installing: the plan is approved and steps run.\n */\n export type Status =\n | \"waiting\"\n | \"planning\"\n | \"installing\"\n | \"done\"\n | \"cancelled\";\n\n /**\n * The agent's proposal to close the checkout. Only the user closes it, and\n * they may keep messaging the agent instead; a later `done` renews it.\n * `preview` is the loopback URL of a dev server the agent left running for\n * the user to try before they close.\n */\n export type Completion = { proposedAt: number; preview?: string };\n\n export type State = {\n version: 2;\n /** The id the browser gave the current checkout; a create with another id replaces it on the same link. */\n id: string | null;\n status: Status;\n completion?: Completion;\n createdAt: number | null;\n products: Product[];\n instructions: string;\n agent: {\n lastSeenAt: number | null;\n /** False once the agent's stream said goodbye; heartbeats set it again. */\n connected: boolean;\n cwd: string | null;\n /** The coding agent that ran the command, as the CLI detected it from its environment. */\n kind: string | null;\n /** When the command was first run against this checkout, before the agent joined the stream. */\n introducedAt: number | null;\n };\n /** Every revision in order; the last one is current. */\n plans: Plan[];\n steps: Step[];\n inputs: Input[];\n log: LogEntry[];\n };\n\n export type ProductSeed = { slug: string; name: string; guide?: string };\n\n export type InputSeed = {\n kind?: InputKind;\n preset?: string;\n prompt: string;\n placeholder?: string;\n options?: ChoiceOption[];\n multiple?: true;\n product?: string;\n default?: string;\n help?: InputHelp;\n redeemKeyHash?: string;\n optional?: boolean;\n };\n\n export type PlanDecision = {\n /** The setup the browser reviewed; omitted by legacy clients. */\n id?: string;\n /** The plan revision the browser reviewed; omitted by legacy clients. */\n revision?: number;\n } & ({ decision: \"approve\" } | { decision: \"revise\"; feedback: string });\n\n export type Commands = {\n \"checkout/create\": (params: {\n id: string;\n products: ProductSeed[];\n instructions?: string;\n }) => void;\n \"checkout/begin-plan\": () => void;\n \"checkout/answer\": (params: {\n inputId: string;\n answer: string;\n note?: string;\n }) => void;\n \"checkout/add-product\": (params: {\n inputId: string;\n product: ProductSeed;\n }) => void;\n \"checkout/message\": (params: { text: string }) => void;\n \"agent/ack\": (params: { messageId: string }) => void;\n \"checkout/dismiss\": (params: { inputId: string }) => void;\n \"checkout/plan\": (params: PlanDecision) => void;\n /** A cancel that names another checkout than the current one is a no-op. */\n \"checkout/cancel\": (params?: { id?: string }) => void;\n \"checkout/finish\": () => void;\n \"agent/intro\": (params: { kind?: string }) => void;\n \"agent/hello\": (params: { cwd?: string; kind?: string }) => void;\n \"agent/heartbeat\": () => void;\n \"agent/bye\": () => void;\n \"agent/plan\": (params: { markdown: string }) => { revision: number };\n \"agent/add-step\": (params: {\n title: string;\n detail?: string;\n product?: string;\n /** Start the step in the same call. */\n active?: boolean;\n }) => { stepId: string };\n \"agent/step\": (params: {\n stepId: string;\n status: StepStatus;\n note?: string;\n }) => void;\n \"agent/ask\": (params: InputSeed & { stepId?: string }) => {\n inputId: string;\n };\n \"agent/log\": (params: { text: string }) => void;\n \"agent/done\": (params?: { summary?: string; preview?: string }) => void;\n };\n\n export type RejectionReason =\n | \"already-created\"\n | \"not-created\"\n | \"closed\"\n | \"planning-not-started\"\n | \"plan-required\"\n | \"no-plan\"\n | \"plan-decided\"\n | \"stale-plan\"\n | \"finish-not-proposed\"\n | \"feedback-required\"\n | \"empty-plan\"\n | \"unknown-step\"\n | \"unknown-product\"\n | \"unknown-input\"\n | \"input-closed\"\n | \"invalid-input\"\n | \"invalid-answer\"\n | \"invalid-preview\"\n | \"empty-message\"\n | \"unknown-message\";\n}\n\nexport const AGENT_PRESENCE_MS = 15_000;\nexport const AGENT_HEARTBEAT_MS = 5_000;\n\nexport const initialCheckoutState = (): Checkout.State => ({\n version: 2,\n id: null,\n status: \"waiting\",\n createdAt: null,\n products: [],\n instructions: \"\",\n agent: {\n lastSeenAt: null,\n connected: false,\n cwd: null,\n kind: null,\n introducedAt: null,\n },\n plans: [],\n steps: [],\n inputs: [],\n log: [],\n});\n\nexport const isAgentPresent = (state: Checkout.State, now = Date.now()) =>\n state.agent.connected &&\n state.agent.lastSeenAt !== null &&\n now - state.agent.lastSeenAt < AGENT_PRESENCE_MS;\n\nexport const isClosed = (state: Checkout.State) =>\n state.status === \"done\" || state.status === \"cancelled\";\n\n/** True while the agent's proposal to close waits for the user. */\nexport const finishProposed = (state: Checkout.State) =>\n !isClosed(state) && state.completion !== undefined;\n\n/** True while a message the user sent after the agent proposed to close still waits for the agent. */\nexport const followedUpSinceProposal = (state: Checkout.State) => {\n const proposedAt = state.completion?.proposedAt;\n return (\n proposedAt !== undefined &&\n state.log.some(\n (entry) =>\n entry.role === \"user\" &&\n entry.at > proposedAt &&\n entry.acknowledgedAt === undefined,\n )\n );\n};\n\nconst LOOPBACK_HOSTS = new Set([\"localhost\", \"127.0.0.1\", \"[::1]\"]);\n\n/**\n * The URL a preview names, or `undefined` unless it is an http(s) URL on this\n * machine's loopback interface. The browser opens it, so nothing else passes.\n */\nexport const parsePreviewUrl = (value: string | undefined) => {\n if (!value) return undefined;\n let url: URL;\n try {\n url = new URL(value);\n } catch {\n return undefined;\n }\n if (url.protocol !== \"http:\" && url.protocol !== \"https:\") return undefined;\n if (url.username !== \"\" || url.password !== \"\") return undefined;\n return isLoopbackHostname(url.hostname) ? url : undefined;\n};\n\n/** True for a hostname that names this machine. */\nexport const isLoopbackHostname = (hostname: string) =>\n LOOPBACK_HOSTS.has(hostname) || hostname.endsWith(\".localhost\");\n\nexport const openInputs = (state: Checkout.State) =>\n state.inputs.filter((input) => input.status === \"open\");\n\n/** The current plan revision, or `undefined` before the agent proposed one. */\nexport const currentPlan = (state: Checkout.State): Checkout.Plan | undefined =>\n state.plans.at(-1);\n\n/** True while a proposed plan waits for the user's decision. */\nexport const planNeedsReview = (state: Checkout.State) =>\n !isClosed(state) && currentPlan(state)?.status === \"proposed\";\n\n/** The icons an agent can put on its own options, by name. */\nexport const OPTION_ICONS = [\n \"code\",\n \"terminal\",\n \"braces\",\n \"git-branch\",\n \"package\",\n \"database\",\n \"server\",\n \"cloud\",\n \"globe\",\n \"monitor\",\n \"smartphone\",\n \"key\",\n \"lock\",\n \"shield\",\n \"brain\",\n \"sparkles\",\n \"bot\",\n \"workflow\",\n \"file\",\n \"folder\",\n \"book\",\n \"table\",\n \"image\",\n \"video\",\n \"mic\",\n \"speech\",\n \"paperclip\",\n \"message\",\n \"mail\",\n \"bell\",\n \"calendar\",\n \"clock\",\n \"user\",\n \"users\",\n \"settings\",\n \"wrench\",\n \"plug\",\n \"link\",\n \"palette\",\n \"search\",\n \"zap\",\n \"check\",\n \"question\",\n] as const;\n\nexport type OptionIcon = (typeof OPTION_ICONS)[number];\n\nexport const isOptionIcon = (value: string): value is OptionIcon =>\n (OPTION_ICONS as readonly string[]).includes(value);\n\nexport const parseChoiceAnswer = (answer: string) => {\n const parts = answer.split(\":\");\n if (parts.length > 2) return { option: answer };\n const [option = \"\", variant] = parts;\n return { option, ...(variant !== undefined && { variant }) };\n};\n\n/** The entries of a multiple choice answer, or `undefined` when the text is not a JSON array of strings. */\nexport const parseMultipleAnswer = (answer: string): string[] | undefined => {\n let value: unknown;\n try {\n value = JSON.parse(answer);\n } catch {\n return undefined;\n }\n return Array.isArray(value) &&\n value.every((entry) => typeof entry === \"string\")\n ? value\n : undefined;\n};\n\ntype ChoiceAnswerKind = \"option\" | \"custom\" | \"invalid\";\n\nconst classifyChoiceEntry = (\n input: Checkout.Input,\n answer: string,\n): ChoiceAnswerKind => {\n const { option, variant } = parseChoiceAnswer(answer);\n const match = input.options?.find((candidate) => candidate.id === option);\n if (!match) return answer.trim() === \"\" ? \"invalid\" : \"custom\";\n if (!match.variants || match.variants.length === 0) {\n return variant === undefined ? \"option\" : \"invalid\";\n }\n return match.variants.some((candidate) => candidate.id === variant)\n ? \"option\"\n : \"invalid\";\n};\n\n/**\n * \"option\" when `answer` names one of the input's options (with a variant\n * when the option has them), \"custom\" for the user's own text, \"invalid\"\n * for an option named without its variant or with an unknown one. A\n * multiple choice is classified entry by entry: \"invalid\" when any entry is\n * or the array is empty, \"custom\" when any entry is the user's own text.\n */\nexport const classifyChoiceAnswer = (\n input: Checkout.Input,\n answer: string,\n): ChoiceAnswerKind => {\n if (!input.multiple) return classifyChoiceEntry(input, answer);\n const entries = parseMultipleAnswer(answer);\n if (!entries || entries.length === 0) return \"invalid\";\n const kinds = entries.map((entry) => classifyChoiceEntry(input, entry));\n if (kinds.includes(\"invalid\")) return \"invalid\";\n return kinds.includes(\"custom\") ? \"custom\" : \"option\";\n};\n\nconst isEntryPointText = (value: unknown, max: number): value is string =>\n typeof value === \"string\" && value.trim() !== \"\" && value.length <= max;\n\nexport const parseEntryPointOptions = (\n value: unknown,\n): Checkout.EntryPointOption[] | undefined => {\n if (!Array.isArray(value) || value.length < 1 || value.length > 3)\n return undefined;\n const options: Checkout.EntryPointOption[] = [];\n for (const candidate of value) {\n if (typeof candidate !== \"object\" || candidate === null) return undefined;\n const { id, label, description, entryPoint, variants } =\n candidate as Record<string, unknown>;\n if (\n typeof id !== \"string\" ||\n !/^[a-zA-Z0-9][a-zA-Z0-9._-]{0,63}$/.test(id) ||\n options.some((option) => option.id === id) ||\n !isEntryPointText(label, 160) ||\n !isEntryPointText(description, 1000) ||\n variants !== undefined ||\n typeof entryPoint !== \"object\" ||\n entryPoint === null\n )\n return undefined;\n const { formFactor, placement, trigger, recommended } =\n entryPoint as Record<string, unknown>;\n if (\n (formFactor !== \"modal\" &&\n formFactor !== \"sidebar\" &&\n formFactor !== \"full-page\") ||\n !isEntryPointText(placement, 400) ||\n !isEntryPointText(trigger, 400) ||\n (recommended !== undefined && typeof recommended !== \"boolean\")\n )\n return undefined;\n options.push({\n id,\n label,\n description,\n entryPoint: {\n formFactor,\n placement,\n trigger,\n ...(recommended !== undefined && { recommended }),\n },\n });\n }\n return options.filter((option) => option.entryPoint.recommended).length <= 1\n ? options\n : undefined;\n};\n\nexport const isValidEntryPointInput = (input: Checkout.InputSeed) => {\n const options = parseEntryPointOptions(input.options);\n return (\n input.kind === \"entry-point\" &&\n isEntryPointText(input.prompt, 1000) &&\n options !== undefined &&\n input.multiple === undefined &&\n input.help === undefined &&\n (input.default === undefined ||\n options.some((option) => option.id === input.default))\n );\n};\n\nexport const isValidEntryPointAnswer = (\n input: Checkout.Input,\n answer: string,\n) => input.options?.some((option) => option.id === answer) ?? false;\n\nconst REASONING_EFFORTS = new Set([\"low\", \"medium\", \"high\"]);\n\nconst isReasoningEffort = (\n value: unknown,\n): value is NonNullable<Checkout.ModelAnswer[\"reasoningEffort\"]> =>\n typeof value === \"string\" && REASONING_EFFORTS.has(value);\n\n/** The model answer an input holds, or `undefined` when the text is not one. */\nexport const parseModelAnswer = (\n answer: string,\n): Checkout.ModelAnswer | undefined => {\n let value: unknown;\n try {\n value = JSON.parse(answer);\n } catch {\n return undefined;\n }\n if (typeof value !== \"object\" || value === null) return undefined;\n const { provider, model, reasoningEffort } = value as Record<string, unknown>;\n if (\n typeof provider !== \"string\" ||\n typeof model !== \"string\" ||\n provider === \"\" ||\n model === \"\"\n ) {\n return undefined;\n }\n if (reasoningEffort === undefined) return { provider, model };\n if (!isReasoningEffort(reasoningEffort)) return undefined;\n return { provider, model, reasoningEffort };\n};\n\n/** Whether `answer` is a model answer naming one of the input's providers. */\nexport const isValidModelAnswer = (input: Checkout.Input, answer: string) => {\n const parsed = parseModelAnswer(answer);\n return (\n parsed !== undefined &&\n (input.options?.some((option) => option.id === parsed.provider) ?? false)\n );\n};\n\nexport const stepProgress = (state: Checkout.State) => ({\n total: state.steps.length,\n done: state.steps.filter(\n (step) => step.status === \"done\" || step.status === \"skipped\",\n ).length,\n});\n"],"mappings":"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"}
1
+ {"version":3,"file":"protocol.js","names":[],"sources":["../src/protocol.ts"],"sourcesContent":["export namespace Checkout {\n export type StepStatus =\n | \"pending\"\n | \"active\"\n | \"done\"\n | \"skipped\"\n | \"blocked\";\n\n /** A unit of install work the agent declared; the catalog seeds none. */\n export type Step = {\n id: string;\n title: string;\n detail?: string;\n status: StepStatus;\n note?: string;\n /** The product this step belongs to, when the agent said. */\n product?: string;\n createdAt: number;\n };\n\n export type Product = {\n slug: string;\n name: string;\n /** The install reference the agent fetches while planning. */\n guide?: string;\n };\n\n export type InputStatus = \"open\" | \"answered\" | \"dismissed\";\n\n /**\n * product: the agent proposes adding a product to this checkout, such as one\n * another product depends on. The browser owns the catalog, so it answers\n * with `checkout/add-product`; dismissing the input declines.\n */\n export type InputKind =\n | \"text\"\n | \"choice\"\n | \"model\"\n | \"product\"\n | \"entry-point\";\n\n export type EntryPoint = {\n formFactor: \"modal\" | \"sidebar\" | \"full-page\";\n placement: string;\n trigger: string;\n recommended?: boolean;\n };\n\n export type EntryPointOption = {\n id: string;\n label: string;\n description: string;\n entryPoint: EntryPoint;\n };\n\n export type ChoiceVariant = { id: string; label: string };\n\n export type ChoiceOption = {\n id: string;\n label: string;\n description?: string;\n /** A name from OPTION_ICONS, or the key of a brand mark on a preset option; unknown keys render without one. */\n icon?: string;\n /** A second pick under this option, such as the language of a framework. */\n variants?: ChoiceVariant[];\n entryPoint?: EntryPoint;\n };\n\n /** A short nudge for users who need help choosing, with a longer guide to link to. */\n export type InputHelp = { summary: string; href?: string };\n\n /**\n * The answer to a model input, stored as JSON text. The API key itself is\n * never part of it: the browser deposits it with the checkout and the\n * agent's `env` command writes it straight to a file.\n */\n export type ModelAnswer = {\n provider: string;\n model: string;\n reasoningEffort?: \"low\" | \"medium\" | \"high\";\n };\n\n /**\n * A choice answer is an option id, `<option>:<variant>` when the option has\n * variants, or the user's own text when none of the options fit; a multiple\n * choice answers a JSON array of those. A model answer is a JSON-encoded\n * ModelAnswer whose provider is one of the options.\n */\n export type Input = {\n phase: Status;\n id: string;\n kind: InputKind;\n /** The standard input this was built from, when it was. */\n preset?: string;\n prompt: string;\n placeholder?: string;\n options?: ChoiceOption[];\n /** The user may pick any number of options; the answer is a JSON array. */\n multiple?: true;\n /** The slug a product input proposes. */\n product?: string;\n default?: string;\n help?: InputHelp;\n redeemKeyHash?: string;\n optional: boolean;\n status: InputStatus;\n answer?: string;\n /** A remark the user attached to the answer. */\n note?: string;\n stepId?: string;\n createdAt: number;\n answeredAt?: number;\n };\n\n export type LogEntry = {\n phase: Status;\n id: string;\n role: \"agent\" | \"user\";\n acknowledgedAt?: number;\n at: number;\n text: string;\n /** The step that was active when the line was posted; none while planning. */\n stepId?: string;\n };\n\n export type PlanStatus = \"proposed\" | \"approved\" | \"changes-requested\";\n\n /** One revision of the agent's plan. Markdown the browser renders. */\n export type Plan = {\n revision: number;\n markdown: string;\n status: PlanStatus;\n submittedAt: number;\n decidedAt?: number;\n /** What the user asked to change, when they did. */\n feedback?: string;\n };\n\n /**\n * waiting: no agent has joined. planning: the agent investigates and\n * proposes a plan. installing: the plan is approved and steps run.\n */\n export type Status =\n | \"waiting\"\n | \"planning\"\n | \"installing\"\n | \"done\"\n | \"cancelled\";\n\n /**\n * The agent's proposal to close the checkout. Only the user closes it, and\n * they may keep messaging the agent instead; a later `done` renews it.\n * `preview` is the loopback URL of a dev server the agent left running for\n * the user to try before they close.\n */\n export type Completion = { proposedAt: number; preview?: string };\n\n export type State = {\n version: 2;\n /** The id the browser gave the current checkout; a create with another id replaces it on the same link. */\n id: string | null;\n status: Status;\n completion?: Completion;\n createdAt: number | null;\n products: Product[];\n instructions: string;\n agent: {\n lastSeenAt: number | null;\n /** False once the agent's stream said goodbye; heartbeats set it again. */\n connected: boolean;\n cwd: string | null;\n /** The coding agent that ran the command, as the CLI detected it from its environment. */\n kind: string | null;\n /** When the command was first run against this checkout, before the agent joined the stream. */\n introducedAt: number | null;\n };\n /**\n * The setup page in the user's browser, while one has joined the link.\n * Absent on hosts older than browser presence.\n */\n browser?: {\n lastSeenAt: number | null;\n /** False once the page said goodbye; heartbeats set it again. */\n connected: boolean;\n };\n /** Every revision in order; the last one is current. */\n plans: Plan[];\n steps: Step[];\n inputs: Input[];\n log: LogEntry[];\n };\n\n export type ProductSeed = { slug: string; name: string; guide?: string };\n\n export type InputSeed = {\n kind?: InputKind;\n preset?: string;\n prompt: string;\n placeholder?: string;\n options?: ChoiceOption[];\n multiple?: true;\n product?: string;\n default?: string;\n help?: InputHelp;\n redeemKeyHash?: string;\n optional?: boolean;\n };\n\n export type PlanDecision = {\n /** The setup the browser reviewed; omitted by legacy clients. */\n id?: string;\n /** The plan revision the browser reviewed; omitted by legacy clients. */\n revision?: number;\n } & ({ decision: \"approve\" } | { decision: \"revise\"; feedback: string });\n\n export type Commands = {\n \"checkout/create\": (params: {\n id: string;\n products: ProductSeed[];\n instructions?: string;\n }) => void;\n \"checkout/begin-plan\": () => void;\n \"checkout/answer\": (params: {\n inputId: string;\n answer: string;\n note?: string;\n }) => void;\n \"checkout/add-product\": (params: {\n inputId: string;\n product: ProductSeed;\n }) => void;\n \"checkout/message\": (params: { text: string }) => void;\n \"agent/ack\": (params: { messageId: string }) => void;\n \"checkout/dismiss\": (params: { inputId: string }) => void;\n \"checkout/plan\": (params: PlanDecision) => void;\n /** A cancel that names another checkout than the current one is a no-op. */\n \"checkout/cancel\": (params?: { id?: string }) => void;\n \"checkout/finish\": () => void;\n \"agent/intro\": (params: { kind?: string }) => void;\n \"agent/hello\": (params: { cwd?: string; kind?: string }) => void;\n \"agent/heartbeat\": () => void;\n \"agent/bye\": () => void;\n /** The setup page is open and joined; sent every BROWSER_HEARTBEAT_MS. */\n \"browser/heartbeat\": () => void;\n /** The setup page is closing. */\n \"browser/bye\": () => void;\n \"agent/plan\": (params: { markdown: string }) => { revision: number };\n \"agent/add-step\": (params: {\n title: string;\n detail?: string;\n product?: string;\n /** Start the step in the same call. */\n active?: boolean;\n }) => { stepId: string };\n \"agent/step\": (params: {\n stepId: string;\n status: StepStatus;\n note?: string;\n }) => void;\n \"agent/ask\": (params: InputSeed & { stepId?: string }) => {\n inputId: string;\n };\n \"agent/log\": (params: { text: string }) => void;\n \"agent/done\": (params?: { summary?: string; preview?: string }) => void;\n };\n\n export type RejectionReason =\n | \"already-created\"\n | \"not-created\"\n | \"closed\"\n | \"planning-not-started\"\n | \"plan-required\"\n | \"no-plan\"\n | \"plan-decided\"\n | \"stale-plan\"\n | \"finish-not-proposed\"\n | \"feedback-required\"\n | \"empty-plan\"\n | \"unknown-step\"\n | \"unknown-product\"\n | \"unknown-input\"\n | \"input-closed\"\n | \"invalid-input\"\n | \"invalid-answer\"\n | \"invalid-preview\"\n | \"empty-message\"\n | \"unknown-message\";\n}\n\nexport const AGENT_PRESENCE_MS = 15_000;\nexport const AGENT_HEARTBEAT_MS = 5_000;\n/** A background tab's timers slow down, so a browser counts as present for longer than an agent. */\nexport const BROWSER_PRESENCE_MS = 20_000;\nexport const BROWSER_HEARTBEAT_MS = 5_000;\n\nexport const initialCheckoutState = (): Checkout.State => ({\n version: 2,\n id: null,\n status: \"waiting\",\n createdAt: null,\n products: [],\n instructions: \"\",\n agent: {\n lastSeenAt: null,\n connected: false,\n cwd: null,\n kind: null,\n introducedAt: null,\n },\n browser: { lastSeenAt: null, connected: false },\n plans: [],\n steps: [],\n inputs: [],\n log: [],\n});\n\nexport const isAgentPresent = (state: Checkout.State, now = Date.now()) =>\n state.agent.connected &&\n state.agent.lastSeenAt !== null &&\n now - state.agent.lastSeenAt < AGENT_PRESENCE_MS;\n\nexport const isClosed = (state: Checkout.State) =>\n state.status === \"done\" || state.status === \"cancelled\";\n\n/** True while the agent's proposal to close waits for the user. */\nexport const finishProposed = (state: Checkout.State) =>\n !isClosed(state) && state.completion !== undefined;\n\n/** True while a message the user sent after the agent proposed to close still waits for the agent. */\nexport const followedUpSinceProposal = (state: Checkout.State) => {\n const proposedAt = state.completion?.proposedAt;\n return (\n proposedAt !== undefined &&\n state.log.some(\n (entry) =>\n entry.role === \"user\" &&\n entry.at > proposedAt &&\n entry.acknowledgedAt === undefined,\n )\n );\n};\n\nconst LOOPBACK_HOSTS = new Set([\"localhost\", \"127.0.0.1\", \"[::1]\"]);\n\n/**\n * The URL a preview names, or `undefined` unless it is an http(s) URL on this\n * machine's loopback interface. The browser opens it, so nothing else passes.\n */\nexport const parsePreviewUrl = (value: string | undefined) => {\n if (!value) return undefined;\n let url: URL;\n try {\n url = new URL(value);\n } catch {\n return undefined;\n }\n if (url.protocol !== \"http:\" && url.protocol !== \"https:\") return undefined;\n if (url.username !== \"\" || url.password !== \"\") return undefined;\n return isLoopbackHostname(url.hostname) ? url : undefined;\n};\n\n/** True for a hostname that names this machine. */\nexport const isLoopbackHostname = (hostname: string) =>\n LOOPBACK_HOSTS.has(hostname) || hostname.endsWith(\".localhost\");\n\nexport const openInputs = (state: Checkout.State) =>\n state.inputs.filter((input) => input.status === \"open\");\n\n/** The current plan revision, or `undefined` before the agent proposed one. */\nexport const currentPlan = (state: Checkout.State): Checkout.Plan | undefined =>\n state.plans.at(-1);\n\n/** True while a proposed plan waits for the user's decision. */\nexport const planNeedsReview = (state: Checkout.State) =>\n !isClosed(state) && currentPlan(state)?.status === \"proposed\";\n\n/** The icons an agent can put on its own options, by name. */\nexport const OPTION_ICONS = [\n \"code\",\n \"terminal\",\n \"braces\",\n \"git-branch\",\n \"package\",\n \"database\",\n \"server\",\n \"cloud\",\n \"globe\",\n \"monitor\",\n \"smartphone\",\n \"key\",\n \"lock\",\n \"shield\",\n \"brain\",\n \"sparkles\",\n \"bot\",\n \"workflow\",\n \"file\",\n \"folder\",\n \"book\",\n \"table\",\n \"image\",\n \"video\",\n \"mic\",\n \"speech\",\n \"paperclip\",\n \"message\",\n \"mail\",\n \"bell\",\n \"calendar\",\n \"clock\",\n \"user\",\n \"users\",\n \"settings\",\n \"wrench\",\n \"plug\",\n \"link\",\n \"palette\",\n \"search\",\n \"zap\",\n \"check\",\n \"question\",\n] as const;\n\nexport type OptionIcon = (typeof OPTION_ICONS)[number];\n\nexport const isOptionIcon = (value: string): value is OptionIcon =>\n (OPTION_ICONS as readonly string[]).includes(value);\n\nexport const parseChoiceAnswer = (answer: string) => {\n const parts = answer.split(\":\");\n if (parts.length > 2) return { option: answer };\n const [option = \"\", variant] = parts;\n return { option, ...(variant !== undefined && { variant }) };\n};\n\n/** The entries of a multiple choice answer, or `undefined` when the text is not a JSON array of strings. */\nexport const parseMultipleAnswer = (answer: string): string[] | undefined => {\n let value: unknown;\n try {\n value = JSON.parse(answer);\n } catch {\n return undefined;\n }\n return Array.isArray(value) &&\n value.every((entry) => typeof entry === \"string\")\n ? value\n : undefined;\n};\n\ntype ChoiceAnswerKind = \"option\" | \"custom\" | \"invalid\";\n\nconst classifyChoiceEntry = (\n input: Checkout.Input,\n answer: string,\n): ChoiceAnswerKind => {\n const { option, variant } = parseChoiceAnswer(answer);\n const match = input.options?.find((candidate) => candidate.id === option);\n if (!match) return answer.trim() === \"\" ? \"invalid\" : \"custom\";\n if (!match.variants || match.variants.length === 0) {\n return variant === undefined ? \"option\" : \"invalid\";\n }\n return match.variants.some((candidate) => candidate.id === variant)\n ? \"option\"\n : \"invalid\";\n};\n\n/**\n * \"option\" when `answer` names one of the input's options (with a variant\n * when the option has them), \"custom\" for the user's own text, \"invalid\"\n * for an option named without its variant or with an unknown one. A\n * multiple choice is classified entry by entry: \"invalid\" when any entry is\n * or the array is empty, \"custom\" when any entry is the user's own text.\n */\nexport const classifyChoiceAnswer = (\n input: Checkout.Input,\n answer: string,\n): ChoiceAnswerKind => {\n if (!input.multiple) return classifyChoiceEntry(input, answer);\n const entries = parseMultipleAnswer(answer);\n if (!entries || entries.length === 0) return \"invalid\";\n const kinds = entries.map((entry) => classifyChoiceEntry(input, entry));\n if (kinds.includes(\"invalid\")) return \"invalid\";\n return kinds.includes(\"custom\") ? \"custom\" : \"option\";\n};\n\nconst isEntryPointText = (value: unknown, max: number): value is string =>\n typeof value === \"string\" && value.trim() !== \"\" && value.length <= max;\n\nexport const parseEntryPointOptions = (\n value: unknown,\n): Checkout.EntryPointOption[] | undefined => {\n if (!Array.isArray(value) || value.length < 1 || value.length > 3)\n return undefined;\n const options: Checkout.EntryPointOption[] = [];\n for (const candidate of value) {\n if (typeof candidate !== \"object\" || candidate === null) return undefined;\n const { id, label, description, entryPoint, variants } =\n candidate as Record<string, unknown>;\n if (\n typeof id !== \"string\" ||\n !/^[a-zA-Z0-9][a-zA-Z0-9._-]{0,63}$/.test(id) ||\n options.some((option) => option.id === id) ||\n !isEntryPointText(label, 160) ||\n !isEntryPointText(description, 1000) ||\n variants !== undefined ||\n typeof entryPoint !== \"object\" ||\n entryPoint === null\n )\n return undefined;\n const { formFactor, placement, trigger, recommended } =\n entryPoint as Record<string, unknown>;\n if (\n (formFactor !== \"modal\" &&\n formFactor !== \"sidebar\" &&\n formFactor !== \"full-page\") ||\n !isEntryPointText(placement, 400) ||\n !isEntryPointText(trigger, 400) ||\n (recommended !== undefined && typeof recommended !== \"boolean\")\n )\n return undefined;\n options.push({\n id,\n label,\n description,\n entryPoint: {\n formFactor,\n placement,\n trigger,\n ...(recommended !== undefined && { recommended }),\n },\n });\n }\n return options.filter((option) => option.entryPoint.recommended).length <= 1\n ? options\n : undefined;\n};\n\nexport const isValidEntryPointInput = (input: Checkout.InputSeed) => {\n const options = parseEntryPointOptions(input.options);\n return (\n input.kind === \"entry-point\" &&\n isEntryPointText(input.prompt, 1000) &&\n options !== undefined &&\n input.multiple === undefined &&\n input.help === undefined &&\n (input.default === undefined ||\n options.some((option) => option.id === input.default))\n );\n};\n\nexport const isValidEntryPointAnswer = (\n input: Checkout.Input,\n answer: string,\n) => input.options?.some((option) => option.id === answer) ?? false;\n\nconst REASONING_EFFORTS = new Set([\"low\", \"medium\", \"high\"]);\n\nconst isReasoningEffort = (\n value: unknown,\n): value is NonNullable<Checkout.ModelAnswer[\"reasoningEffort\"]> =>\n typeof value === \"string\" && REASONING_EFFORTS.has(value);\n\n/** The model answer an input holds, or `undefined` when the text is not one. */\nexport const parseModelAnswer = (\n answer: string,\n): Checkout.ModelAnswer | undefined => {\n let value: unknown;\n try {\n value = JSON.parse(answer);\n } catch {\n return undefined;\n }\n if (typeof value !== \"object\" || value === null) return undefined;\n const { provider, model, reasoningEffort } = value as Record<string, unknown>;\n if (\n typeof provider !== \"string\" ||\n typeof model !== \"string\" ||\n provider === \"\" ||\n model === \"\"\n ) {\n return undefined;\n }\n if (reasoningEffort === undefined) return { provider, model };\n if (!isReasoningEffort(reasoningEffort)) return undefined;\n return { provider, model, reasoningEffort };\n};\n\n/** Whether `answer` is a model answer naming one of the input's providers. */\nexport const isValidModelAnswer = (input: Checkout.Input, answer: string) => {\n const parsed = parseModelAnswer(answer);\n return (\n parsed !== undefined &&\n (input.options?.some((option) => option.id === parsed.provider) ?? false)\n );\n};\n\nexport const stepProgress = (state: Checkout.State) => ({\n total: state.steps.length,\n done: state.steps.filter(\n (step) => step.status === \"done\" || step.status === \"skipped\",\n ).length,\n});\n"],"mappings":"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"}
package/dist/sdk.d.ts ADDED
@@ -0,0 +1,48 @@
1
+ import type { CheckoutClient } from "./client.js";
2
+ import type { Checkout } from "./protocol.js";
3
+ import type { FollowSetupOptions } from "./stream.js";
4
+ export type SetupSession = {
5
+ linkId: string;
6
+ setupId: string;
7
+ /** The URL every setup command takes. */
8
+ agentUrl: string;
9
+ /** The page the user follows the setup on. */
10
+ browserUrl: string;
11
+ products: Checkout.ProductSeed[];
12
+ };
13
+ export type RunAgentSetupOptions = {
14
+ /** The setup server, such as https://checkout.assistant-ui.com. */
15
+ server: string;
16
+ /** The setup app the browser opens, such as https://setup.assistant-ui.com. */
17
+ setupAppUrl: string;
18
+ products: Checkout.ProductSeed[];
19
+ /** How the agent invokes setup commands, before the URL: `npx assistant-ui@latest setup`. */
20
+ command: string;
21
+ /** What the product calls this, for the briefing's first line. */
22
+ name?: string;
23
+ /** False for `--no-open`: the agent asks the user itself. */
24
+ canOpen?: boolean;
25
+ /** Opens the setup page; the default browser by default. */
26
+ open?: (url: string) => void;
27
+ /** Called once the session exists, before the briefing prints. */
28
+ onSession?: (session: SetupSession) => void;
29
+ write?: (text: string) => void;
30
+ env?: NodeJS.ProcessEnv;
31
+ connect?: (url: string) => Promise<CheckoutClient>;
32
+ stream?: Pick<FollowSetupOptions, "print" | "agent">;
33
+ };
34
+ /**
35
+ * `<tool> setup` for a coding agent, in one call: opens a new link on the
36
+ * setup server, creates a setup there and starts planning, prints the
37
+ * briefing, then streams the setup and opens the browser only when it waits
38
+ * on the user. Resolves with the running stream; the caller stops it (on
39
+ * SIGINT, say) and disposes the client.
40
+ */
41
+ export declare const runAgentSetup: (options: RunAgentSetupOptions) => Promise<{
42
+ session: SetupSession;
43
+ stream: {
44
+ stop: () => Promise<void>;
45
+ };
46
+ client: CheckoutClient;
47
+ }>;
48
+ //# sourceMappingURL=sdk.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"sdk.d.ts","sourceRoot":"","sources":["../src/sdk.ts"],"names":[],"mappings":"AASA,OAAO,KAAK,EAAE,cAAc,EAAE,oBAAiB;AAC/C,OAAO,KAAK,EAAE,QAAQ,EAAE,sBAAmB;AAE3C,OAAO,KAAK,EAAE,kBAAkB,EAAE,oBAAiB;AAYnD,MAAM,MAAM,YAAY,GAAG;IACzB,MAAM,EAAE,MAAM,CAAC;IACf,OAAO,EAAE,MAAM,CAAC;IAChB,yCAAyC;IACzC,QAAQ,EAAE,MAAM,CAAC;IACjB,8CAA8C;IAC9C,UAAU,EAAE,MAAM,CAAC;IACnB,QAAQ,EAAE,QAAQ,CAAC,WAAW,EAAE,CAAC;CAClC,CAAC;AAEF,MAAM,MAAM,oBAAoB,GAAG;IACjC,mEAAmE;IACnE,MAAM,EAAE,MAAM,CAAC;IACf,+EAA+E;IAC/E,WAAW,EAAE,MAAM,CAAC;IACpB,QAAQ,EAAE,QAAQ,CAAC,WAAW,EAAE,CAAC;IACjC,6FAA6F;IAC7F,OAAO,EAAE,MAAM,CAAC;IAChB,kEAAkE;IAClE,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,6DAA6D;IAC7D,OAAO,CAAC,EAAE,OAAO,CAAC;IAClB,4DAA4D;IAC5D,IAAI,CAAC,EAAE,CAAC,GAAG,EAAE,MAAM,KAAK,IAAI,CAAC;IAC7B,kEAAkE;IAClE,SAAS,CAAC,EAAE,CAAC,OAAO,EAAE,YAAY,KAAK,IAAI,CAAC;IAC5C,KAAK,CAAC,EAAE,CAAC,IAAI,EAAE,MAAM,KAAK,IAAI,CAAC;IAC/B,GAAG,CAAC,EAAE,MAAM,CAAC,UAAU,CAAC;IACxB,OAAO,CAAC,EAAE,CAAC,GAAG,EAAE,MAAM,KAAK,OAAO,CAAC,cAAc,CAAC,CAAC;IACnD,MAAM,CAAC,EAAE,IAAI,CAAC,kBAAkB,EAAE,OAAO,GAAG,OAAO,CAAC,CAAC;CACtD,CAAC;AAuCF;;;;;;GAMG;AACH,eAAO,MAAM,aAAa,GAAU,SAAS,oBAAoB;;;;;;EA4ChE,CAAC"}