setup-agent 0.1.0 → 0.1.2

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.
@@ -1 +1 @@
1
- {"version":3,"file":"client.d.ts","sourceRoot":"","sources":["../src/client.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,eAAe,EAAiB,MAAM,WAAW,CAAC;AAC3D,OAAO,KAAK,EAAE,QAAQ,EAAE,sBAAmB;AAE3C,MAAM,MAAM,cAAc,GAAG,eAAe,CAC1C,QAAQ,CAAC,KAAK,GAAG,SAAS,EAC1B,QAAQ,CAAC,QAAQ,CAClB,CAAC;AAEF,gFAAgF;AAChF,eAAO,MAAM,eAAe,GAAI,KAAK,MAAM,KAAG,OAAO,CAAC,cAAc,CAiChE,CAAC"}
1
+ {"version":3,"file":"client.d.ts","sourceRoot":"","sources":["../src/client.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,eAAe,EAAiB,MAAM,WAAW,CAAC;AAC3D,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,eAAY,CAAC;AAE3C,MAAM,MAAM,cAAc,GAAG,eAAe,CAC1C,QAAQ,CAAC,KAAK,GAAG,SAAS,EAC1B,QAAQ,CAAC,QAAQ,CAClB,CAAC;AAEF,gFAAgF;AAChF,eAAO,MAAM,eAAe,QAAS,MAAM,KAAG,OAAO,CAAC,cAAc,CAiChE,CAAC"}
@@ -1 +1 @@
1
- {"version":3,"file":"host.d.ts","sourceRoot":"","sources":["../src/host.ts"],"names":[],"mappings":"AAmBA,OAAO,KAAK,EAAE,QAAQ,EAAE,sBAAmB;AA+d3C,6EAA6E;AAC7E,eAAO,MAAM,YAAY,GAAI,WAAW,OAAO;;;;0BARrB,MAAM,IAAI;EASC,CAAC;AAEtC,YAAY,EAAE,QAAQ,EAAE,sBAAmB"}
1
+ {"version":3,"file":"host.d.ts","sourceRoot":"","sources":["../src/host.ts"],"names":[],"mappings":"AAmBA,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,eAAY,CAAC;AA+d3C,6EAA6E;AAC7E,eAAO,MAAM,YAAY,cAAe,OAAO;;;;0BARrB,MAAM,IAAI;EASC,CAAC;AAEtC,YAAY,EAAE,QAAQ,EAAE,MAAM,eAAY,CAAC"}
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,YAAY,EAAE,QAAQ,EAAE,UAAU,EAAE,sBAAmB;AACvD,OAAO,EACL,kBAAkB,EAClB,iBAAiB,EACjB,oBAAoB,EACpB,YAAY,EACZ,oBAAoB,EACpB,WAAW,EACX,oBAAoB,EACpB,cAAc,EACd,uBAAuB,EACvB,cAAc,EACd,QAAQ,EACR,YAAY,EACZ,kBAAkB,EAClB,uBAAuB,EACvB,sBAAsB,EACtB,UAAU,EACV,iBAAiB,EACjB,sBAAsB,EACtB,gBAAgB,EAChB,mBAAmB,EACnB,eAAe,EACf,eAAe,EACf,YAAY,GACb,sBAAmB;AACpB,OAAO,EAAE,aAAa,EAAE,UAAU,EAAE,WAAW,EAAE,qBAAkB;AACnE,YAAY,EAAE,QAAQ,EAAE,eAAe,EAAE,qBAAkB;AAC3D,OAAO,EAAE,eAAe,EAAE,oBAAiB;AAC3C,YAAY,EAAE,cAAc,EAAE,oBAAiB"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,YAAY,EAAE,QAAQ,EAAE,UAAU,EAAE,MAAM,eAAY,CAAC;AACvD,OAAO,EACL,kBAAkB,EAClB,iBAAiB,EACjB,oBAAoB,EACpB,YAAY,EACZ,oBAAoB,EACpB,WAAW,EACX,oBAAoB,EACpB,cAAc,EACd,uBAAuB,EACvB,cAAc,EACd,QAAQ,EACR,YAAY,EACZ,kBAAkB,EAClB,uBAAuB,EACvB,sBAAsB,EACtB,UAAU,EACV,iBAAiB,EACjB,sBAAsB,EACtB,gBAAgB,EAChB,mBAAmB,EACnB,eAAe,EACf,eAAe,EACf,YAAY,GACb,MAAM,eAAY,CAAC;AACpB,OAAO,EAAE,aAAa,EAAE,UAAU,EAAE,WAAW,EAAE,MAAM,cAAW,CAAC;AACnE,YAAY,EAAE,QAAQ,EAAE,eAAe,EAAE,MAAM,cAAW,CAAC;AAC3D,OAAO,EAAE,eAAe,EAAE,MAAM,aAAU,CAAC;AAC3C,YAAY,EAAE,cAAc,EAAE,MAAM,aAAU,CAAC"}
package/dist/needs.d.ts CHANGED
@@ -53,10 +53,10 @@ export declare const answerNeed: (client: Pick<CheckoutClient, "state" | "comman
53
53
  decision: string;
54
54
  status?: never;
55
55
  } | {
56
+ decision?: never;
56
57
  ok: boolean;
57
58
  id: string;
58
59
  status: string;
59
- decision?: never;
60
60
  }>;
61
61
  export {};
62
62
  //# sourceMappingURL=needs.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"needs.d.ts","sourceRoot":"","sources":["../src/needs.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,cAAc,EAAE,oBAAiB;AAY/C,OAAO,KAAK,EAAE,QAAQ,EAAE,sBAAmB;AAE3C;;;;GAIG;AACH,MAAM,MAAM,SAAS,GACjB;IAAE,EAAE,EAAE,MAAM,CAAC;IAAC,IAAI,EAAE,OAAO,CAAC;IAAC,KAAK,EAAE,QAAQ,CAAC,KAAK,CAAA;CAAE,GACpD;IAAE,EAAE,EAAE,MAAM,CAAC;IAAC,IAAI,EAAE,MAAM,CAAC;IAAC,IAAI,EAAE,QAAQ,CAAC,IAAI,CAAA;CAAE,GACjD;IAAE,EAAE,EAAE,QAAQ,CAAC;IAAC,IAAI,EAAE,QAAQ,CAAC;IAAC,UAAU,EAAE,QAAQ,CAAC,UAAU,CAAA;CAAE,CAAC;AAEtE,oEAAoE;AACpE,eAAO,MAAM,YAAY,GAAI,OAAO,QAAQ,CAAC,KAAK,KAAG,SAAS,EAoB7D,CAAC;AAEF,qFAAqF;AACrF,eAAO,MAAM,OAAO,GAAI,MAAM,SAAS,WAKO,CAAC;AAE/C,KAAK,UAAU,GAAG;IAAE,EAAE,EAAE,MAAM,CAAC;IAAC,KAAK,EAAE,MAAM,CAAC;IAAC,WAAW,CAAC,EAAE,MAAM,CAAA;CAAE,CAAC;AAEtE,kFAAkF;AAClF,MAAM,MAAM,gBAAgB,GAAG;IAC7B,QAAQ,EAAE,MAAM,CAAC;IACjB,OAAO,CAAC,EAAE,UAAU,EAAE,CAAC;IACvB,QAAQ,CAAC,EAAE,IAAI,CAAC;IAChB,iEAAiE;IACjE,YAAY,EAAE,MAAM,CAAC;CACtB,CAAC;AAgCF,eAAO,MAAM,gBAAgB,GAAI,MAAM,SAAS,KAAG,gBAoClD,CAAC;AAEF,8DAA8D;AAC9D,eAAO,MAAM,sBAAsB,GAAI,kCAIpC,gBAAgB,WAQL,CAAC;AAsDf;;;;GAIG;AACH,eAAO,MAAM,UAAU,GACrB,QAAQ,IAAI,CAAC,cAAc,EAAE,OAAO,GAAG,UAAU,CAAC,EAClD,IAAI,MAAM,EACV,OAAO,MAAM,GAAG,SAAS,EACzB,UAAS;IAAE,IAAI,CAAC,EAAE,MAAM,CAAC;IAAC,QAAQ,CAAC,EAAE,MAAM,CAAC;IAAC,OAAO,CAAC,EAAE,OAAO,CAAA;CAAO;;;;;;;;;;EA8DtE,CAAC"}
1
+ {"version":3,"file":"needs.d.ts","sourceRoot":"","sources":["../src/needs.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,aAAU,CAAC;AAY/C,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,eAAY,CAAC;AAE3C;;;;GAIG;AACH,MAAM,MAAM,SAAS,GACjB;IAAE,EAAE,EAAE,MAAM,CAAC;IAAC,IAAI,EAAE,OAAO,CAAC;IAAC,KAAK,EAAE,QAAQ,CAAC,KAAK,CAAA;CAAE,GACpD;IAAE,EAAE,EAAE,MAAM,CAAC;IAAC,IAAI,EAAE,MAAM,CAAC;IAAC,IAAI,EAAE,QAAQ,CAAC,IAAI,CAAA;CAAE,GACjD;IAAE,EAAE,EAAE,QAAQ,CAAC;IAAC,IAAI,EAAE,QAAQ,CAAC;IAAC,UAAU,EAAE,QAAQ,CAAC,UAAU,CAAA;CAAE,CAAC;AAEtE,oEAAoE;AACpE,eAAO,MAAM,YAAY,UAAW,QAAQ,CAAC,KAAK,KAAG,SAAS,EAoB7D,CAAC;AAEF,qFAAqF;AACrF,eAAO,MAAM,OAAO,SAAU,SAAS,WAKO,CAAC;AAE/C,KAAK,UAAU,GAAG;IAAE,EAAE,EAAE,MAAM,CAAC;IAAC,KAAK,EAAE,MAAM,CAAC;IAAC,WAAW,CAAC,EAAE,MAAM,CAAA;CAAE,CAAC;AAEtE,kFAAkF;AAClF,MAAM,MAAM,gBAAgB,GAAG;IAC7B,QAAQ,EAAE,MAAM,CAAC;IACjB,OAAO,CAAC,EAAE,UAAU,EAAE,CAAC;IACvB,QAAQ,CAAC,EAAE,IAAI,CAAC;IAChB,iEAAiE;IACjE,YAAY,EAAE,MAAM,CAAC;CACtB,CAAC;AAgCF,eAAO,MAAM,gBAAgB,SAAU,SAAS,KAAG,gBAoClD,CAAC;AAEF,8DAA8D;AAC9D,eAAO,MAAM,sBAAsB,qCAIhC,gBAAgB,WAQL,CAAC;AAsDf;;;;GAIG;AACH,eAAO,MAAM,UAAU,WACb,IAAI,CAAC,cAAc,EAAE,OAAO,GAAG,UAAU,CAAC,MAC9C,MAAM,SACH,MAAM,GAAG,SAAS,YAChB;IAAE,IAAI,CAAC,EAAE,MAAM,CAAC;IAAC,QAAQ,CAAC,EAAE,MAAM,CAAC;IAAC,OAAO,CAAC,EAAE,OAAO,CAAA;CAAE;;;;;;;;;;EA8DjE,CAAC"}
@@ -1 +1 @@
1
- {"version":3,"file":"presets.d.ts","sourceRoot":"","sources":["../src/presets.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,QAAQ,EAAE,sBAAmB;AAO3C,MAAM,MAAM,QAAQ,GAAG,WAAW,GAAG,cAAc,GAAG,SAAS,CAAC;AAEhE,MAAM,MAAM,eAAe,GAAG;IAC5B,oFAAoF;IACpF,IAAI,CAAC,EAAE,SAAS,MAAM,EAAE,CAAC;IACzB,8FAA8F;IAC9F,KAAK,CAAC,EAAE,SAAS;QAAE,EAAE,EAAE,MAAM,CAAC;QAAC,WAAW,CAAC,EAAE,MAAM,CAAA;KAAE,EAAE,CAAC;IACxD,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,QAAQ,CAAC,EAAE,OAAO,CAAC;IACnB,MAAM,CAAC,EAAE,MAAM,CAAC;CACjB,CAAC;AAEF,KAAK,MAAM,GAAG;IACZ,IAAI,EAAE,QAAQ,CAAC,SAAS,CAAC;IACzB,MAAM,EAAE,MAAM,CAAC;IACf,OAAO,EAAE,QAAQ,CAAC,YAAY,EAAE,CAAC;IACjC,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,IAAI,EAAE,QAAQ,CAAC,SAAS,CAAC;CAC1B,CAAC;AAEF,qEAAqE;AACrE,eAAO,MAAM,aAAa,EAAE,MAAM,CAAC,QAAQ,EAAE,MAAM,CA+GlD,CAAC;AAEF,eAAO,MAAM,UAAU,GAAI,IAAI,MAAM,KAAG,EAAE,IAAI,QACZ,CAAC;AAEnC,6FAA6F;AAC7F,eAAO,MAAM,WAAW,GACtB,IAAI,QAAQ,EACZ,YAAW,eAAoB,KAC9B,QAAQ,CAAC,SAAS,GAAG;IAAE,MAAM,CAAC,EAAE,MAAM,CAAA;CAqCxC,CAAC"}
1
+ {"version":3,"file":"presets.d.ts","sourceRoot":"","sources":["../src/presets.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,eAAY,CAAC;AAO3C,MAAM,MAAM,QAAQ,GAAG,WAAW,GAAG,cAAc,GAAG,SAAS,CAAC;AAEhE,MAAM,MAAM,eAAe,GAAG;IAC5B,oFAAoF;IACpF,IAAI,CAAC,EAAE,SAAS,MAAM,EAAE,CAAC;IACzB,8FAA8F;IAC9F,KAAK,CAAC,EAAE,SAAS;QAAE,EAAE,EAAE,MAAM,CAAC;QAAC,WAAW,CAAC,EAAE,MAAM,CAAA;KAAE,EAAE,CAAC;IACxD,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,QAAQ,CAAC,EAAE,OAAO,CAAC;IACnB,MAAM,CAAC,EAAE,MAAM,CAAC;CACjB,CAAC;AAEF,KAAK,MAAM,GAAG;IACZ,IAAI,EAAE,QAAQ,CAAC,SAAS,CAAC;IACzB,MAAM,EAAE,MAAM,CAAC;IACf,OAAO,EAAE,QAAQ,CAAC,YAAY,EAAE,CAAC;IACjC,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,IAAI,EAAE,QAAQ,CAAC,SAAS,CAAC;CAC1B,CAAC;AAEF,qEAAqE;AACrE,eAAO,MAAM,aAAa,EAAE,MAAM,CAAC,QAAQ,EAAE,MAAM,CA+GlD,CAAC;AAEF,eAAO,MAAM,UAAU,OAAQ,MAAM,KAAG,EAAE,IAAI,QACZ,CAAC;AAEnC,6FAA6F;AAC7F,eAAO,MAAM,WAAW,OAClB,QAAQ,cACD,eAAe,KACzB,QAAQ,CAAC,SAAS,GAAG;IAAE,MAAM,CAAC,EAAE,MAAM,CAAA;CAqCxC,CAAC"}
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":";AAEA,MAAM,aAAa;CAAE,IAAI;CAAc,OAAO;AAAa;AAC3D,MAAM,SAAS;CAAE,IAAI;CAAU,OAAO;AAAS;AAE/C,MAAM,OAAO;;AAuBb,MAAa,gBAA0C;CACrD,WAAW;EACT,MAAM;EACN,QAAQ;EACR,SAAS;GACP;IACE,IAAI;IACJ,OAAO;IACP,aAAa;IACb,MAAM;IACN,UAAU,CAAC,UAAU;GACvB;GACA;IACE,IAAI;IACJ,OAAO;IACP,aAAa;IACb,MAAM;IACN,UAAU,CAAC,UAAU;GACvB;GACA;IACE,IAAI;IACJ,OAAO;IACP,aAAa;IACb,MAAM;IACN,UAAU,CAAC,QAAQ,UAAU;GAC/B;EACF;EACA,MAAM;GACJ,SACE;GACF,MAAM,GAAG,KAAK;EAChB;CACF;CACA,gBAAgB;EACd,MAAM;EACN,QAAQ;EACR,SAAS;GACP;IACE,IAAI;IACJ,OAAO;IACP,aAAa;IACb,MAAM;GACR;GACA;IACE,IAAI;IACJ,OAAO;IACP,aAAa;IACb,MAAM;GACR;GACA;IACE,IAAI;IACJ,OAAO;IACP,aAAa;IACb,MAAM;GACR;GACA;IACE,IAAI;IACJ,OAAO;IACP,aAAa;IACb,MAAM;GACR;GACA;IAAE,IAAI;IAAO,OAAO;IAAO,aAAa;IAAe,MAAM;GAAM;GACnE;IACE,IAAI;IACJ,OAAO;IACP,aAAa;IACb,MAAM;GACR;GACA;IACE,IAAI;IACJ,OAAO;IACP,aAAa;IACb,MAAM;GACR;GACA;IAAE,IAAI;IAAQ,OAAO;IAAQ,aAAa;IAAgB,MAAM;GAAO;GACvE;IACE,IAAI;IACJ,OAAO;IACP,aAAa;IACb,MAAM;GACR;EACF;EACA,SAAS;EACT,MAAM,EACJ,SACE,6IACJ;CACF;CACA,SAAS;EACP,MAAM;EACN,QAAQ;EACR,SAAS,CACP;GACE,IAAI;GACJ,OAAO;GACP,aAAa;GACb,UAAU;IACR;KAAE,IAAI;KAAQ,OAAO;IAAU;IAC/B;KAAE,IAAI;KAAQ,OAAO;IAAO;IAC5B;KAAE,IAAI;KAAgB,OAAO;IAAe;IAC5C;KAAE,IAAI;KAAkB,OAAO;IAAiB;IAChD;KAAE,IAAI;KAAQ,OAAO;IAAO;GAC9B;EACF,CACF;EACA,MAAM;GACJ,SACE;GACF,MAAM,GAAG,KAAK;EAChB;CACF;AACF;AAEA,MAAa,cAAc,OACzB,OAAO,OAAO,eAAe,EAAE;;AAGjC,MAAa,eACX,IACA,YAA6B,CAAC,MACe;CAC7C,MAAM,SAAS,cAAc;CAC7B,MAAM,SAAS,UAAU,OACrB,UAAU,KAAK,KAAK,aAAa;EAC/B,MAAM,SAAS,OAAO,QAAQ,MAAM,MAAM,EAAE,OAAO,QAAQ;EAC3D,IAAI,CAAC,QACH,MAAM,IAAI,MAAM,WAAW,GAAG,mBAAmB,SAAS,EAAE;EAC9D,OAAO;CACT,CAAC,IACD,OAAO;CACX,MAAM,SAAS,UAAU,SAAS,CAAC,EAAA,CAAG,KAAK,WAAW;EACpD,IACE,OAAO,GAAG,SAAS,GAAG,KACtB,OAAO,QAAQ,MAAM,MAAM,EAAE,OAAO,OAAO,EAAE,GAE7C,MAAM,IAAI,MAAM,WAAW,GAAG,iBAAiB,OAAO,GAAG,eAAe;EAE1E,OAAO;GAAE,GAAG;GAAQ,OAAO,OAAO;EAAG;CACvC,CAAC;CACD,MAAM,UAAU,UAAU,OAAO,SAAS,CAAC,GAAG,OAAO,GAAG,MAAM;CAC9D,MAAM,WAAW,QAAQ,MAAM,MAAM,EAAE,OAAO,OAAO,OAAO,IACxD,OAAO,UACP,KAAA;CACJ,MAAM,SAAS,UAAU,WAAW;CACpC,IAAI,WAAW,KAAA,KAAa,CAAC,QAAQ,MAAM,MAAM,EAAE,OAAO,MAAM,GAC9D,MAAM,IAAI,MAAM,WAAW,GAAG,mBAAmB,OAAO,gBAAgB;CAE1E,OAAO;EACL,MAAM,OAAO;EACb,QAAQ;EACR,QAAQ,OAAO;EACf;EACA,GAAI,WAAW,KAAA,KAAa,EAAE,SAAS,OAAO;EAC9C,MAAM,OAAO;EACb,UAAU,UAAU,YAAY;EAChC,GAAI,UAAU,WAAW,KAAA,KAAa,EAAE,QAAQ,UAAU,OAAO;CACnE;AACF"}
@@ -302,8 +302,8 @@ export declare const OPTION_ICONS: readonly ["code", "terminal", "braces", "git-
302
302
  export type OptionIcon = (typeof OPTION_ICONS)[number];
303
303
  export declare const isOptionIcon: (value: string) => value is OptionIcon;
304
304
  export declare const parseChoiceAnswer: (answer: string) => {
305
- variant?: string;
306
305
  option: string;
306
+ variant?: string;
307
307
  };
308
308
  /** The entries of a multiple choice answer, or `undefined` when the text is not a JSON array of strings. */
309
309
  export declare const parseMultipleAnswer: (answer: string) => string[] | undefined;
@@ -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/sdk.d.ts.map CHANGED
@@ -1 +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"}
1
+ {"version":3,"file":"sdk.d.ts","sourceRoot":"","sources":["../src/sdk.ts"],"names":[],"mappings":"AASA,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,aAAU,CAAC;AAC/C,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,eAAY,CAAC;AAE3C,OAAO,KAAK,EAAE,kBAAkB,EAAE,MAAM,aAAU,CAAC;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,YAAmB,oBAAoB;;;;;;EA4ChE,CAAC"}
package/dist/sdk.js CHANGED
@@ -18,7 +18,7 @@ const setupBriefing = (session, { command, name = "Setup", canOpen = true }) =>
18
18
 
19
19
  1. Keep it running in the background until the setup ends. If you started it in the foreground, stop it and resume it in the background (Claude Code: Bash with run_in_background; Codex and other agents: add > "\${TMPDIR:-/tmp}/setup-${session.linkId}.log" 2>&1 & and read that file):
20
20
  ${command} ${url} stream${canOpen ? "" : " --no-open"}
21
- 2. Read its new output as it arrives. Each line after this briefing is a JSON array of events.
21
+ 2. Its new output does not wake you, so never end your turn to wait for it. Read the new lines between your other commands; each line after this briefing is a JSON array of events. Answers reach you through the blocking "wait" commands below.
22
22
  3. Run every other command in another shell: ${command} ${url} <command>.
23
23
  4. ${canOpen ? "Setup opens the user's browser by itself when you ask the user something; do not open it yourself." : `Setup will not open a browser (--no-open). Give the user ${session.browserUrl} once, or ask in your own conversation.`} On an "input.needed" event, do what its message says; to answer from here, run its "answer" command with the user's reply.
24
24
 
package/dist/sdk.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"file":"sdk.js","names":[],"sources":["../src/sdk.ts"],"sourcesContent":["/**\n * `<tool> setup` for coding agents, for a CLI to embed. `runAgentSetup` is\n * the whole command; route `<tool> setup <url> <step> ...` to\n * `runSetupCommand` from `setup-agent/cli`. Node only.\n */\nimport { randomInt } from \"node:crypto\";\nimport { detectAgentKind } from \"./agents\";\nimport { agentInstructions } from \"./cli\";\nimport { connectCheckout } from \"./client\";\nimport type { CheckoutClient } from \"./client\";\nimport type { Checkout } from \"./protocol\";\nimport { followSetup, setupPageUrl, shellWord } from \"./stream\";\nimport type { FollowSetupOptions } from \"./stream\";\n\n/** A random id in the alphabet and length the setup page uses for its own. */\nconst createSetupId = () =>\n Array.from(\n { length: 12 },\n () =>\n \"ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789\"[\n randomInt(62)\n ]!,\n ).join(\"\");\n\nexport type SetupSession = {\n linkId: string;\n setupId: string;\n /** The URL every setup command takes. */\n agentUrl: string;\n /** The page the user follows the setup on. */\n browserUrl: string;\n products: Checkout.ProductSeed[];\n};\n\nexport type RunAgentSetupOptions = {\n /** The setup server, such as https://checkout.assistant-ui.com. */\n server: string;\n /** The setup app the browser opens, such as https://setup.assistant-ui.com. */\n setupAppUrl: string;\n products: Checkout.ProductSeed[];\n /** How the agent invokes setup commands, before the URL: `npx assistant-ui@latest setup`. */\n command: string;\n /** What the product calls this, for the briefing's first line. */\n name?: string;\n /** False for `--no-open`: the agent asks the user itself. */\n canOpen?: boolean;\n /** Opens the setup page; the default browser by default. */\n open?: (url: string) => void;\n /** Called once the session exists, before the briefing prints. */\n onSession?: (session: SetupSession) => void;\n write?: (text: string) => void;\n env?: NodeJS.ProcessEnv;\n connect?: (url: string) => Promise<CheckoutClient>;\n stream?: Pick<FollowSetupOptions, \"print\" | \"agent\">;\n};\n\n/** What the agent reads first in the output of a setup command that keeps running. */\nconst setupBriefing = (\n session: SetupSession,\n {\n command,\n name = \"Setup\",\n canOpen = true,\n }: Pick<RunAgentSetupOptions, \"command\" | \"name\" | \"canOpen\">,\n) => {\n const url = shellWord(session.agentUrl);\n return `${name} is running. This command keeps running: it is the setup's stream.\n\n1. Keep it running in the background until the setup ends. If you started it in the foreground, stop it and resume it in the background (Claude Code: Bash with run_in_background; Codex and other agents: add > \"\\${TMPDIR:-/tmp}/setup-${session.linkId}.log\" 2>&1 & and read that file):\n ${command} ${url} stream${canOpen ? \"\" : \" --no-open\"}\n2. Read its new output as it arrives. Each line after this briefing is a JSON array of events.\n3. Run every other command in another shell: ${command} ${url} <command>.\n4. ${\n canOpen\n ? \"Setup opens the user's browser by itself when you ask the user something; do not open it yourself.\"\n : `Setup will not open a browser (--no-open). Give the user ${session.browserUrl} once, or ask in your own conversation.`\n } On an \"input.needed\" event, do what its message says; to answer from here, run its \"answer\" command with the user's reply.\n\n${agentInstructions(session.agentUrl, {\n command,\n startedByAgent: {\n browserUrl: session.browserUrl,\n streaming: true,\n opened: canOpen,\n },\n})}\nSetup page, if the user asks for it: ${session.browserUrl}\n\nCurrent setup:\n${JSON.stringify({ status: \"planning\", products: session.products })}\n`;\n};\n\n/**\n * `<tool> setup` for a coding agent, in one call: opens a new link on the\n * setup server, creates a setup there and starts planning, prints the\n * briefing, then streams the setup and opens the browser only when it waits\n * on the user. Resolves with the running stream; the caller stops it (on\n * SIGINT, say) and disposes the client.\n */\nexport const runAgentSetup = async (options: RunAgentSetupOptions) => {\n const connect = options.connect ?? connectCheckout;\n const linkId = createSetupId();\n const setupId = createSetupId();\n const agentUrl = `${options.server.replace(/\\/$/, \"\")}/${linkId}`;\n const client = await connect(agentUrl);\n try {\n const kind = detectAgentKind(options.env);\n await client.commands[\"checkout/create\"]({\n id: setupId,\n products: options.products,\n });\n await client.commands[\"checkout/begin-plan\"]();\n // The agent shows as connected once the stream says hello with the cwd.\n await client.commands[\"agent/intro\"]({\n ...(kind !== undefined && { kind }),\n });\n const session: SetupSession = {\n linkId,\n setupId,\n agentUrl,\n browserUrl: setupPageUrl(options.setupAppUrl, linkId, setupId),\n products: options.products,\n };\n options.onSession?.(session);\n (options.write ?? ((text) => process.stdout.write(text)))(\n setupBriefing(session, options),\n );\n const stream = await followSetup(client, {\n ...options.stream,\n agent: { ...(kind !== undefined && { kind }), ...options.stream?.agent },\n browser: {\n setupAppUrl: options.setupAppUrl,\n linkId,\n answerCommand: `${options.command} ${shellWord(agentUrl)} answer`,\n ...(options.open && { open: options.open }),\n ...(options.canOpen !== undefined && { canOpen: options.canOpen }),\n },\n });\n return { session, stream, client };\n } catch (error) {\n client.dispose();\n throw error;\n }\n};\n"],"mappings":";;;;;;;;;;;;AAeA,MAAM,sBACJ,MAAM,KACJ,EAAE,QAAQ,GAAG,SAEX,iEACE,UAAU,EAAE,EAElB,CAAC,CAAC,KAAK,EAAE;;AAmCX,MAAM,iBACJ,SACA,EACE,SACA,OAAO,SACP,UAAU,WAET;CACH,MAAM,MAAM,UAAU,QAAQ,QAAQ;CACtC,OAAO,GAAG,KAAK;;2OAE0N,QAAQ,OAAO;IACtP,QAAQ,GAAG,IAAI,SAAS,UAAU,KAAK,aAAa;;+CAET,QAAQ,GAAG,IAAI;KAE1D,UACI,uGACA,4DAA4D,QAAQ,WAAW,yCACpF;;EAED,kBAAkB,QAAQ,UAAU;EACpC;EACA,gBAAgB;GACd,YAAY,QAAQ;GACpB,WAAW;GACX,QAAQ;EACV;CACF,CAAC,EAAE;uCACoC,QAAQ,WAAW;;;EAGxD,KAAK,UAAU;EAAE,QAAQ;EAAY,UAAU,QAAQ;CAAS,CAAC,EAAE;;AAErE;;;;;;;;AASA,MAAa,gBAAgB,OAAO,YAAkC;CACpE,MAAM,UAAU,QAAQ,WAAW;CACnC,MAAM,SAAS,cAAc;CAC7B,MAAM,UAAU,cAAc;CAC9B,MAAM,WAAW,GAAG,QAAQ,OAAO,QAAQ,OAAO,EAAE,EAAE,GAAG;CACzD,MAAM,SAAS,MAAM,QAAQ,QAAQ;CACrC,IAAI;EACF,MAAM,OAAO,gBAAgB,QAAQ,GAAG;EACxC,MAAM,OAAO,SAAS,kBAAkB,CAAC;GACvC,IAAI;GACJ,UAAU,QAAQ;EACpB,CAAC;EACD,MAAM,OAAO,SAAS,sBAAsB,CAAC;EAE7C,MAAM,OAAO,SAAS,cAAc,CAAC,EACnC,GAAI,SAAS,KAAA,KAAa,EAAE,KAAK,EACnC,CAAC;EACD,MAAM,UAAwB;GAC5B;GACA;GACA;GACA,YAAY,aAAa,QAAQ,aAAa,QAAQ,OAAO;GAC7D,UAAU,QAAQ;EACpB;EACA,QAAQ,YAAY,OAAO;EAC3B,CAAC,QAAQ,WAAW,SAAS,QAAQ,OAAO,MAAM,IAAI,GAAA,CACpD,cAAc,SAAS,OAAO,CAChC;EAYA,OAAO;GAAE;GAAS,QAAA,MAXG,YAAY,QAAQ;IACvC,GAAG,QAAQ;IACX,OAAO;KAAE,GAAI,SAAS,KAAA,KAAa,EAAE,KAAK;KAAI,GAAG,QAAQ,QAAQ;IAAM;IACvE,SAAS;KACP,aAAa,QAAQ;KACrB;KACA,eAAe,GAAG,QAAQ,QAAQ,GAAG,UAAU,QAAQ,EAAE;KACzD,GAAI,QAAQ,QAAQ,EAAE,MAAM,QAAQ,KAAK;KACzC,GAAI,QAAQ,YAAY,KAAA,KAAa,EAAE,SAAS,QAAQ,QAAQ;IAClE;GACF,CAAC;GACyB;EAAO;CACnC,SAAS,OAAO;EACd,OAAO,QAAQ;EACf,MAAM;CACR;AACF"}
1
+ {"version":3,"file":"sdk.js","names":[],"sources":["../src/sdk.ts"],"sourcesContent":["/**\n * `<tool> setup` for coding agents, for a CLI to embed. `runAgentSetup` is\n * the whole command; route `<tool> setup <url> <step> ...` to\n * `runSetupCommand` from `setup-agent/cli`. Node only.\n */\nimport { randomInt } from \"node:crypto\";\nimport { detectAgentKind } from \"./agents\";\nimport { agentInstructions } from \"./cli\";\nimport { connectCheckout } from \"./client\";\nimport type { CheckoutClient } from \"./client\";\nimport type { Checkout } from \"./protocol\";\nimport { followSetup, setupPageUrl, shellWord } from \"./stream\";\nimport type { FollowSetupOptions } from \"./stream\";\n\n/** A random id in the alphabet and length the setup page uses for its own. */\nconst createSetupId = () =>\n Array.from(\n { length: 12 },\n () =>\n \"ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789\"[\n randomInt(62)\n ]!,\n ).join(\"\");\n\nexport type SetupSession = {\n linkId: string;\n setupId: string;\n /** The URL every setup command takes. */\n agentUrl: string;\n /** The page the user follows the setup on. */\n browserUrl: string;\n products: Checkout.ProductSeed[];\n};\n\nexport type RunAgentSetupOptions = {\n /** The setup server, such as https://checkout.assistant-ui.com. */\n server: string;\n /** The setup app the browser opens, such as https://setup.assistant-ui.com. */\n setupAppUrl: string;\n products: Checkout.ProductSeed[];\n /** How the agent invokes setup commands, before the URL: `npx assistant-ui@latest setup`. */\n command: string;\n /** What the product calls this, for the briefing's first line. */\n name?: string;\n /** False for `--no-open`: the agent asks the user itself. */\n canOpen?: boolean;\n /** Opens the setup page; the default browser by default. */\n open?: (url: string) => void;\n /** Called once the session exists, before the briefing prints. */\n onSession?: (session: SetupSession) => void;\n write?: (text: string) => void;\n env?: NodeJS.ProcessEnv;\n connect?: (url: string) => Promise<CheckoutClient>;\n stream?: Pick<FollowSetupOptions, \"print\" | \"agent\">;\n};\n\n/** What the agent reads first in the output of a setup command that keeps running. */\nconst setupBriefing = (\n session: SetupSession,\n {\n command,\n name = \"Setup\",\n canOpen = true,\n }: Pick<RunAgentSetupOptions, \"command\" | \"name\" | \"canOpen\">,\n) => {\n const url = shellWord(session.agentUrl);\n return `${name} is running. This command keeps running: it is the setup's stream.\n\n1. Keep it running in the background until the setup ends. If you started it in the foreground, stop it and resume it in the background (Claude Code: Bash with run_in_background; Codex and other agents: add > \"\\${TMPDIR:-/tmp}/setup-${session.linkId}.log\" 2>&1 & and read that file):\n ${command} ${url} stream${canOpen ? \"\" : \" --no-open\"}\n2. Its new output does not wake you, so never end your turn to wait for it. Read the new lines between your other commands; each line after this briefing is a JSON array of events. Answers reach you through the blocking \"wait\" commands below.\n3. Run every other command in another shell: ${command} ${url} <command>.\n4. ${\n canOpen\n ? \"Setup opens the user's browser by itself when you ask the user something; do not open it yourself.\"\n : `Setup will not open a browser (--no-open). Give the user ${session.browserUrl} once, or ask in your own conversation.`\n } On an \"input.needed\" event, do what its message says; to answer from here, run its \"answer\" command with the user's reply.\n\n${agentInstructions(session.agentUrl, {\n command,\n startedByAgent: {\n browserUrl: session.browserUrl,\n streaming: true,\n opened: canOpen,\n },\n})}\nSetup page, if the user asks for it: ${session.browserUrl}\n\nCurrent setup:\n${JSON.stringify({ status: \"planning\", products: session.products })}\n`;\n};\n\n/**\n * `<tool> setup` for a coding agent, in one call: opens a new link on the\n * setup server, creates a setup there and starts planning, prints the\n * briefing, then streams the setup and opens the browser only when it waits\n * on the user. Resolves with the running stream; the caller stops it (on\n * SIGINT, say) and disposes the client.\n */\nexport const runAgentSetup = async (options: RunAgentSetupOptions) => {\n const connect = options.connect ?? connectCheckout;\n const linkId = createSetupId();\n const setupId = createSetupId();\n const agentUrl = `${options.server.replace(/\\/$/, \"\")}/${linkId}`;\n const client = await connect(agentUrl);\n try {\n const kind = detectAgentKind(options.env);\n await client.commands[\"checkout/create\"]({\n id: setupId,\n products: options.products,\n });\n await client.commands[\"checkout/begin-plan\"]();\n // The agent shows as connected once the stream says hello with the cwd.\n await client.commands[\"agent/intro\"]({\n ...(kind !== undefined && { kind }),\n });\n const session: SetupSession = {\n linkId,\n setupId,\n agentUrl,\n browserUrl: setupPageUrl(options.setupAppUrl, linkId, setupId),\n products: options.products,\n };\n options.onSession?.(session);\n (options.write ?? ((text) => process.stdout.write(text)))(\n setupBriefing(session, options),\n );\n const stream = await followSetup(client, {\n ...options.stream,\n agent: { ...(kind !== undefined && { kind }), ...options.stream?.agent },\n browser: {\n setupAppUrl: options.setupAppUrl,\n linkId,\n answerCommand: `${options.command} ${shellWord(agentUrl)} answer`,\n ...(options.open && { open: options.open }),\n ...(options.canOpen !== undefined && { canOpen: options.canOpen }),\n },\n });\n return { session, stream, client };\n } catch (error) {\n client.dispose();\n throw error;\n }\n};\n"],"mappings":";;;;;;;;;;;;AAeA,MAAM,sBACJ,MAAM,KACJ,EAAE,QAAQ,GAAG,SAEX,iEACE,UAAU,EAAE,EAElB,CAAC,CAAC,KAAK,EAAE;;AAmCX,MAAM,iBACJ,SACA,EACE,SACA,OAAO,SACP,UAAU,WAET;CACH,MAAM,MAAM,UAAU,QAAQ,QAAQ;CACtC,OAAO,GAAG,KAAK;;2OAE0N,QAAQ,OAAO;IACtP,QAAQ,GAAG,IAAI,SAAS,UAAU,KAAK,aAAa;;+CAET,QAAQ,GAAG,IAAI;KAE1D,UACI,uGACA,4DAA4D,QAAQ,WAAW,yCACpF;;EAED,kBAAkB,QAAQ,UAAU;EACpC;EACA,gBAAgB;GACd,YAAY,QAAQ;GACpB,WAAW;GACX,QAAQ;EACV;CACF,CAAC,EAAE;uCACoC,QAAQ,WAAW;;;EAGxD,KAAK,UAAU;EAAE,QAAQ;EAAY,UAAU,QAAQ;CAAS,CAAC,EAAE;;AAErE;;;;;;;;AASA,MAAa,gBAAgB,OAAO,YAAkC;CACpE,MAAM,UAAU,QAAQ,WAAW;CACnC,MAAM,SAAS,cAAc;CAC7B,MAAM,UAAU,cAAc;CAC9B,MAAM,WAAW,GAAG,QAAQ,OAAO,QAAQ,OAAO,EAAE,EAAE,GAAG;CACzD,MAAM,SAAS,MAAM,QAAQ,QAAQ;CACrC,IAAI;EACF,MAAM,OAAO,gBAAgB,QAAQ,GAAG;EACxC,MAAM,OAAO,SAAS,kBAAkB,CAAC;GACvC,IAAI;GACJ,UAAU,QAAQ;EACpB,CAAC;EACD,MAAM,OAAO,SAAS,sBAAsB,CAAC;EAE7C,MAAM,OAAO,SAAS,cAAc,CAAC,EACnC,GAAI,SAAS,KAAA,KAAa,EAAE,KAAK,EACnC,CAAC;EACD,MAAM,UAAwB;GAC5B;GACA;GACA;GACA,YAAY,aAAa,QAAQ,aAAa,QAAQ,OAAO;GAC7D,UAAU,QAAQ;EACpB;EACA,QAAQ,YAAY,OAAO;EAC3B,CAAC,QAAQ,WAAW,SAAS,QAAQ,OAAO,MAAM,IAAI,GAAA,CACpD,cAAc,SAAS,OAAO,CAChC;EAYA,OAAO;GAAE;GAAS,QAAA,MAXG,YAAY,QAAQ;IACvC,GAAG,QAAQ;IACX,OAAO;KAAE,GAAI,SAAS,KAAA,KAAa,EAAE,KAAK;KAAI,GAAG,QAAQ,QAAQ;IAAM;IACvE,SAAS;KACP,aAAa,QAAQ;KACrB;KACA,eAAe,GAAG,QAAQ,QAAQ,GAAG,UAAU,QAAQ,EAAE;KACzD,GAAI,QAAQ,QAAQ,EAAE,MAAM,QAAQ,KAAK;KACzC,GAAI,QAAQ,YAAY,KAAA,KAAa,EAAE,SAAS,QAAQ,QAAQ;IAClE;GACF,CAAC;GACyB;EAAO;CACnC,SAAS,OAAO;EACd,OAAO,QAAQ;EACf,MAAM;CACR;AACF"}
package/dist/stream.d.ts CHANGED
@@ -53,9 +53,9 @@ export type StreamEvent = {
53
53
  } & TerminalQuestion);
54
54
  export declare const diffEvents: (before: Checkout.State, after: Checkout.State) => StreamEvent[];
55
55
  export declare const answerFields: (input: Checkout.Input, answer: string) => {
56
- custom?: true;
57
- note?: string;
58
56
  answer: string | string[];
57
+ note?: string;
58
+ custom?: true;
59
59
  };
60
60
  /** The setup page that joins a link; the link rides in the fragment, which never reaches a server. */
61
61
  export declare const setupPageUrl: (setupAppUrl: string, linkId: string, setupId: string) => string;
@@ -1 +1 @@
1
- {"version":3,"file":"stream.d.ts","sourceRoot":"","sources":["../src/stream.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"stream.d.ts","sourceRoot":"","sources":["../src/stream.ts"],"names":[],"mappings":"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"}
package/dist/stream.js CHANGED
@@ -80,18 +80,21 @@ const openUrl = (url) => {
80
80
  /** `value` as one shell word, quoted only when it holds more than plain URL characters. */
81
81
  const shellWord = (value) => /^[A-Za-z0-9._~%/:@=+,-]+$/.test(value) ? value : `'${value.replaceAll("'", `'\\''`)}'`;
82
82
  const ASK_MESSAGES = {
83
- "recently-opened": (question, { agoSeconds }) => `A browser tab for setup was opened ${agoSeconds}s ago. Wait for the user there, or ask the user directly in the terminal: ${question}`,
83
+ "recently-opened": (question, { agoSeconds, wait }) => `A browser tab for setup was opened ${agoSeconds}s ago. Wait for the user there${wait}, or ask the user directly in the terminal: ${question}`,
84
84
  "browser-closed": (question) => `The user closed the setup tab. Ask the user directly in the terminal: ${question}`,
85
85
  "no-browser": (question, { page }) => `No browser tab is open for this setup. Ask the user directly in the terminal, or give them ${page}: ${question}`
86
86
  };
87
+ /** The command that blocks on a need, beside the one that answers it: `<cmd> <url> wait`. */
88
+ const waitCommandFor = (answerCommand) => answerCommand.endsWith(" answer") ? `${answerCommand.slice(0, -7)} wait` : void 0;
87
89
  /** What the agent reads when setup opened the browser, or when it should ask the user itself. */
88
- const gateEvent = (action, answerCommand, page) => {
90
+ const gateEvent = (action, answerCommand, page, waitCommand) => {
89
91
  const { need } = action;
92
+ const wait = waitCommand !== void 0 && need.kind !== "finish" ? ` with "${waitCommand} ${need.id}"` : "";
90
93
  if (action.type === "open") return {
91
94
  event: "browser.opened",
92
95
  id: need.id,
93
96
  url: action.url,
94
- message: `Opened the setup in the user's browser for ${need.kind === "input" ? `"${need.input.prompt.trim() || "Your agent needs an answer."}"` : need.kind === "plan" ? "the plan review" : "closing the setup"}. Tell the user once that it is waiting there, and give them ${action.url} in case it did not open. The answer arrives on this stream.`
97
+ message: `Opened the setup in the user's browser for ${need.kind === "input" ? `"${need.input.prompt.trim() || "Your agent needs an answer."}"` : need.kind === "plan" ? "the plan review" : "closing the setup"}. Tell the user once that it is waiting there, and give them ${action.url} in case it did not open.${need.kind === "finish" ? " The answer arrives on this stream." : ` Then keep working in the same turn; when you need the answer, block on it${wait || " with \"wait\""}. Do not end your turn to wait: nothing on this stream wakes you.`}`
95
98
  };
96
99
  const question = terminalQuestion(need);
97
100
  return {
@@ -100,7 +103,8 @@ const gateEvent = (action, answerCommand, page) => {
100
103
  reason: action.reason,
101
104
  message: ASK_MESSAGES[action.reason](formatTerminalQuestion(question), {
102
105
  agoSeconds: Math.round((action.openedAgoMs ?? 0) / 1e3),
103
- page
106
+ page,
107
+ wait
104
108
  }),
105
109
  ...question,
106
110
  answer: `${answerCommand} ${need.id} <${question.answerFormat}>`
@@ -138,7 +142,7 @@ const followSetup = async (client, { print, agent, browser } = {}) => {
138
142
  const runGate = (state) => {
139
143
  for (const action of gate?.update(state) ?? []) {
140
144
  if (action.type === "open") (browser.open ?? openUrl)(action.url);
141
- pending.push(gateEvent(action, browser.answerCommand, page(state) ?? ""));
145
+ pending.push(gateEvent(action, browser.answerCommand, page(state) ?? "", waitCommandFor(browser.answerCommand)));
142
146
  }
143
147
  };
144
148
  const unsubscribe = client.subscribe(() => {
@@ -1 +1 @@
1
- {"version":3,"file":"stream.js","names":[],"sources":["../src/stream.ts"],"sourcesContent":["import spawn from \"cross-spawn\";\nimport { detectAgentKind } from \"./agents\";\nimport { createBrowserGate } from \"./browser\";\nimport type { AskReason, BrowserGateAction } from \"./browser\";\nimport type { CheckoutClient } from \"./client\";\nimport { formatTerminalQuestion, terminalQuestion } from \"./needs\";\nimport type { TerminalQuestion } from \"./needs\";\nimport {\n AGENT_HEARTBEAT_MS,\n classifyChoiceAnswer,\n parseMultipleAnswer,\n} from \"./protocol\";\nimport type { Checkout } from \"./protocol\";\n\nexport type StreamEvent =\n | { event: \"planning.started\" }\n | { event: \"message.created\"; messageId: string; text: string }\n | {\n event: \"input.answered\";\n inputId: string;\n prompt: string;\n /** The entries of a multiple choice answer, else the answer text. */\n answer: string | string[];\n note?: string;\n /** True when a choice answer is, or a multiple one contains, the user's own text rather than an option. */\n custom?: true;\n }\n | { event: \"input.dismissed\"; inputId: string; prompt: string }\n | { event: \"plan.approved\"; revision: number }\n | { event: \"plan.changes-requested\"; revision: number; feedback: string }\n | { event: \"finished\"; next: string }\n | { event: \"cancelled\"; next: string }\n | { event: \"setup.created\"; products: string[] }\n | {\n event: \"browser.opened\";\n /** The need the tab opened for: an input id, plan or finish. */\n id: string;\n url: string;\n message: string;\n }\n | ({\n event: \"input.needed\";\n id: string;\n reason: AskReason;\n message: string;\n /** The command that answers it, with the answer's shape in angle brackets. */\n answer: string;\n } & TerminalQuestion);\n\nconst STAY_CONNECTED =\n \"This setup is over, not your connection. Keep the stream running, tell the user you are connected and waiting for their next setup, and run wait start.\";\n\nexport const diffEvents = (\n before: Checkout.State,\n after: Checkout.State,\n): StreamEvent[] => {\n const events: StreamEvent[] = [];\n if (before.status === \"waiting\" && after.status === \"planning\") {\n events.push({ event: \"planning.started\" });\n }\n for (const entry of after.log) {\n if (\n entry.role === \"user\" &&\n entry.acknowledgedAt === undefined &&\n !before.log.some((previous) => previous.id === entry.id)\n ) {\n events.push({\n event: \"message.created\",\n messageId: entry.id,\n text: entry.text,\n });\n }\n }\n for (const input of after.inputs) {\n const previous = before.inputs.find(\n (candidate) => candidate.id === input.id,\n );\n if (previous?.status === input.status) continue;\n if (input.status === \"answered\") {\n const answer = input.answer ?? \"\";\n events.push({\n event: \"input.answered\",\n inputId: input.id,\n prompt: input.prompt,\n ...answerFields(input, answer),\n });\n } else if (input.status === \"dismissed\" && after.status !== \"cancelled\") {\n events.push({\n event: \"input.dismissed\",\n inputId: input.id,\n prompt: input.prompt,\n });\n }\n }\n for (const plan of after.plans) {\n const previous = before.plans.find(\n (candidate) => candidate.revision === plan.revision,\n );\n if (previous?.status === plan.status || plan.status === \"proposed\") {\n continue;\n }\n if (plan.status === \"approved\") {\n events.push({ event: \"plan.approved\", revision: plan.revision });\n } else {\n events.push({\n event: \"plan.changes-requested\",\n revision: plan.revision,\n feedback: plan.feedback ?? \"\",\n });\n }\n }\n if (before.status !== \"done\" && after.status === \"done\") {\n events.push({ event: \"finished\", next: STAY_CONNECTED });\n }\n if (before.status !== \"cancelled\" && after.status === \"cancelled\") {\n events.push({ event: \"cancelled\", next: STAY_CONNECTED });\n }\n if (after.id !== null && after.id !== before.id) {\n events.push({\n event: \"setup.created\",\n products: after.products.map((product) => product.slug),\n });\n }\n return events;\n};\n\nexport const answerFields = (input: Checkout.Input, answer: string) => ({\n answer: (input.multiple && parseMultipleAnswer(answer)) || answer,\n ...(input.note !== undefined && { note: input.note }),\n ...(input.kind === \"choice\" &&\n classifyChoiceAnswer(input, answer) === \"custom\" && {\n custom: true as const,\n }),\n});\n\n/** The setup page that joins a link; the link rides in the fragment, which never reaches a server. */\nexport const setupPageUrl = (\n setupAppUrl: string,\n linkId: string,\n setupId: string,\n) => `${setupAppUrl.replace(/\\/$/, \"\")}/#link=${linkId}&setup=${setupId}`;\n\n/**\n * Opens `url` in the user's default browser without waiting for it.\n * `SETUP_AGENT_BROWSER` names another program to run with the URL instead,\n * such as a test driver.\n */\nconst openUrl = (url: string) => {\n const custom = process.env.SETUP_AGENT_BROWSER?.trim();\n const [command, args] = custom\n ? [custom, [url]]\n : process.platform === \"darwin\"\n ? [\"open\", [url]]\n : process.platform === \"win32\"\n ? [\"rundll32\", [\"url.dll,FileProtocolHandler\", url]]\n : [\"xdg-open\", [url]];\n const child = spawn(command, args, { detached: true, stdio: \"ignore\" });\n child.on(\"error\", () => {});\n child.unref();\n};\n\n/** `value` as one shell word, quoted only when it holds more than plain URL characters. */\nexport const shellWord = (value: string) =>\n /^[A-Za-z0-9._~%/:@=+,-]+$/.test(value)\n ? value\n : `'${value.replaceAll(\"'\", `'\\\\''`)}'`;\n\nconst ASK_MESSAGES: Record<\n AskReason,\n (question: string, context: { agoSeconds: number; page: string }) => string\n> = {\n \"recently-opened\": (question, { agoSeconds }) =>\n `A browser tab for setup was opened ${agoSeconds}s ago. Wait for the user there, or ask the user directly in the terminal: ${question}`,\n \"browser-closed\": (question) =>\n `The user closed the setup tab. Ask the user directly in the terminal: ${question}`,\n \"no-browser\": (question, { page }) =>\n `No browser tab is open for this setup. Ask the user directly in the terminal, or give them ${page}: ${question}`,\n};\n\n/** What the agent reads when setup opened the browser, or when it should ask the user itself. */\nconst gateEvent = (\n action: BrowserGateAction,\n answerCommand: string,\n page: string,\n): StreamEvent => {\n const { need } = action;\n if (action.type === \"open\")\n return {\n event: \"browser.opened\",\n id: need.id,\n url: action.url,\n message: `Opened the setup in the user's browser for ${need.kind === \"input\" ? `\"${need.input.prompt.trim() || \"Your agent needs an answer.\"}\"` : need.kind === \"plan\" ? \"the plan review\" : \"closing the setup\"}. Tell the user once that it is waiting there, and give them ${action.url} in case it did not open. The answer arrives on this stream.`,\n };\n const question = terminalQuestion(need);\n return {\n event: \"input.needed\",\n id: need.id,\n reason: action.reason,\n message: ASK_MESSAGES[action.reason](formatTerminalQuestion(question), {\n agoSeconds: Math.round((action.openedAgoMs ?? 0) / 1000),\n page,\n }),\n ...question,\n answer: `${answerCommand} ${need.id} <${question.answerFormat}>`,\n };\n};\n\nexport type FollowSetupOptions = {\n /** Writes one line of events; the default prints a JSON array to stdout. */\n print?: (events: StreamEvent[]) => void;\n /** The agent the stream reports in its hello; detected by default. */\n agent?: { cwd?: string; kind?: string };\n /** Opens the setup page when the setup waits on the user; without it, the stream never opens one. */\n browser?: {\n setupAppUrl: string;\n linkId: string;\n /** The command that answers a need, before the need id: `npx assistant-ui@latest setup <url> answer`. */\n answerCommand: string;\n open?: (url: string) => void;\n /** False for `--no-open`: the agent is told to ask instead. */\n canOpen?: boolean;\n now?: () => number;\n };\n};\n\n/**\n * Follows a setup as the agent: says hello, keeps the agent present with\n * heartbeats, prints what changed as stream events, and opens the browser\n * only when the setup waits on the user. Resolves with `stop`, which says\n * goodbye; the caller disposes the client.\n */\nexport const followSetup = async (\n client: Pick<CheckoutClient, \"state\" | \"subscribe\" | \"commands\">,\n { print, agent, browser }: FollowSetupOptions = {},\n) => {\n const write =\n print ??\n ((events: StreamEvent[]) => {\n process.stdout.write(`${JSON.stringify(events)}\\n`);\n });\n const page = (state: Checkout.State) =>\n browser && state.id !== null\n ? setupPageUrl(browser.setupAppUrl, browser.linkId, state.id)\n : undefined;\n const gate =\n browser &&\n createBrowserGate({\n url: page,\n ...(browser.canOpen !== undefined && { canOpen: browser.canOpen }),\n ...(browser.now !== undefined && { now: browser.now }),\n });\n let previous = client.state;\n if (previous === undefined) throw new Error(\"the setup has no state\");\n let pending = diffEvents({ ...previous, log: [] }, previous);\n let timer: ReturnType<typeof setTimeout> | undefined;\n const flush = () => {\n clearTimeout(timer);\n timer = undefined;\n if (pending.length > 0) write(pending);\n pending = [];\n };\n const runGate = (state: Checkout.State) => {\n for (const action of gate?.update(state) ?? []) {\n if (action.type === \"open\") (browser!.open ?? openUrl)(action.url);\n pending.push(\n gateEvent(action, browser!.answerCommand, page(state) ?? \"\"),\n );\n }\n };\n const unsubscribe = client.subscribe(() => {\n const next = client.state;\n if (next === undefined) return;\n pending.push(...diffEvents(previous!, next));\n previous = next;\n runGate(next);\n if (pending.length > 0 && timer === undefined)\n timer = setTimeout(flush, 200);\n });\n runGate(previous);\n flush();\n // Presence lapses without a state change, so the gate also looks every second.\n const tick =\n gate &&\n setInterval(() => {\n runGate(previous!);\n flush();\n }, 1_000);\n const kind = agent?.kind ?? detectAgentKind();\n try {\n await client.commands[\"agent/hello\"]({\n cwd: agent?.cwd ?? process.cwd(),\n ...(kind !== undefined && { kind }),\n });\n } catch (error) {\n clearInterval(tick);\n clearTimeout(timer);\n unsubscribe();\n throw error;\n }\n const heartbeat = setInterval(() => {\n void client.commands[\"agent/heartbeat\"]().catch(() => {});\n }, AGENT_HEARTBEAT_MS);\n let stopped: Promise<void> | undefined;\n return {\n stop: () =>\n (stopped ??= (async () => {\n clearInterval(heartbeat);\n clearInterval(tick);\n unsubscribe();\n flush();\n await client.commands[\"agent/bye\"]().catch(() => {});\n })()),\n };\n};\n"],"mappings":";;;;;;AAiDA,MAAM,iBACJ;AAEF,MAAa,cACX,QACA,UACkB;CAClB,MAAM,SAAwB,CAAC;CAC/B,IAAI,OAAO,WAAW,aAAa,MAAM,WAAW,YAClD,OAAO,KAAK,EAAE,OAAO,mBAAmB,CAAC;CAE3C,KAAK,MAAM,SAAS,MAAM,KACxB,IACE,MAAM,SAAS,UACf,MAAM,mBAAmB,KAAA,KACzB,CAAC,OAAO,IAAI,MAAM,aAAa,SAAS,OAAO,MAAM,EAAE,GAEvD,OAAO,KAAK;EACV,OAAO;EACP,WAAW,MAAM;EACjB,MAAM,MAAM;CACd,CAAC;CAGL,KAAK,MAAM,SAAS,MAAM,QAAQ;EAIhC,IAHiB,OAAO,OAAO,MAC5B,cAAc,UAAU,OAAO,MAAM,EAE7B,CAAC,EAAE,WAAW,MAAM,QAAQ;EACvC,IAAI,MAAM,WAAW,YAAY;GAC/B,MAAM,SAAS,MAAM,UAAU;GAC/B,OAAO,KAAK;IACV,OAAO;IACP,SAAS,MAAM;IACf,QAAQ,MAAM;IACd,GAAG,aAAa,OAAO,MAAM;GAC/B,CAAC;EACH,OAAO,IAAI,MAAM,WAAW,eAAe,MAAM,WAAW,aAC1D,OAAO,KAAK;GACV,OAAO;GACP,SAAS,MAAM;GACf,QAAQ,MAAM;EAChB,CAAC;CAEL;CACA,KAAK,MAAM,QAAQ,MAAM,OAAO;EAI9B,IAHiB,OAAO,MAAM,MAC3B,cAAc,UAAU,aAAa,KAAK,QAElC,CAAC,EAAE,WAAW,KAAK,UAAU,KAAK,WAAW,YACtD;EAEF,IAAI,KAAK,WAAW,YAClB,OAAO,KAAK;GAAE,OAAO;GAAiB,UAAU,KAAK;EAAS,CAAC;OAE/D,OAAO,KAAK;GACV,OAAO;GACP,UAAU,KAAK;GACf,UAAU,KAAK,YAAY;EAC7B,CAAC;CAEL;CACA,IAAI,OAAO,WAAW,UAAU,MAAM,WAAW,QAC/C,OAAO,KAAK;EAAE,OAAO;EAAY,MAAM;CAAe,CAAC;CAEzD,IAAI,OAAO,WAAW,eAAe,MAAM,WAAW,aACpD,OAAO,KAAK;EAAE,OAAO;EAAa,MAAM;CAAe,CAAC;CAE1D,IAAI,MAAM,OAAO,QAAQ,MAAM,OAAO,OAAO,IAC3C,OAAO,KAAK;EACV,OAAO;EACP,UAAU,MAAM,SAAS,KAAK,YAAY,QAAQ,IAAI;CACxD,CAAC;CAEH,OAAO;AACT;AAEA,MAAa,gBAAgB,OAAuB,YAAoB;CACtE,QAAS,MAAM,YAAY,oBAAoB,MAAM,KAAM;CAC3D,GAAI,MAAM,SAAS,KAAA,KAAa,EAAE,MAAM,MAAM,KAAK;CACnD,GAAI,MAAM,SAAS,YACjB,qBAAqB,OAAO,MAAM,MAAM,YAAY,EAClD,QAAQ,KACV;AACJ;;AAGA,MAAa,gBACX,aACA,QACA,YACG,GAAG,YAAY,QAAQ,OAAO,EAAE,EAAE,SAAS,OAAO,SAAS;;;;;;AAOhE,MAAM,WAAW,QAAgB;CAC/B,MAAM,SAAS,QAAQ,IAAI,qBAAqB,KAAK;CACrD,MAAM,CAAC,SAAS,QAAQ,SACpB,CAAC,QAAQ,CAAC,GAAG,CAAC,IACd,QAAQ,aAAa,WACnB,CAAC,QAAQ,CAAC,GAAG,CAAC,IACd,QAAQ,aAAa,UACnB,CAAC,YAAY,CAAC,+BAA+B,GAAG,CAAC,IACjD,CAAC,YAAY,CAAC,GAAG,CAAC;CAC1B,MAAM,QAAQ,MAAM,SAAS,MAAM;EAAE,UAAU;EAAM,OAAO;CAAS,CAAC;CACtE,MAAM,GAAG,eAAe,CAAC,CAAC;CAC1B,MAAM,MAAM;AACd;;AAGA,MAAa,aAAa,UACxB,4BAA4B,KAAK,KAAK,IAClC,QACA,IAAI,MAAM,WAAW,KAAK,OAAO,EAAE;AAEzC,MAAM,eAGF;CACF,oBAAoB,UAAU,EAAE,iBAC9B,sCAAsC,WAAW,4EAA4E;CAC/H,mBAAmB,aACjB,yEAAyE;CAC3E,eAAe,UAAU,EAAE,WACzB,8FAA8F,KAAK,IAAI;AAC3G;;AAGA,MAAM,aACJ,QACA,eACA,SACgB;CAChB,MAAM,EAAE,SAAS;CACjB,IAAI,OAAO,SAAS,QAClB,OAAO;EACL,OAAO;EACP,IAAI,KAAK;EACT,KAAK,OAAO;EACZ,SAAS,8CAA8C,KAAK,SAAS,UAAU,IAAI,KAAK,MAAM,OAAO,KAAK,KAAK,8BAA8B,KAAK,KAAK,SAAS,SAAS,oBAAoB,oBAAoB,+DAA+D,OAAO,IAAI;CAC7R;CACF,MAAM,WAAW,iBAAiB,IAAI;CACtC,OAAO;EACL,OAAO;EACP,IAAI,KAAK;EACT,QAAQ,OAAO;EACf,SAAS,aAAa,OAAO,OAAO,CAAC,uBAAuB,QAAQ,GAAG;GACrE,YAAY,KAAK,OAAO,OAAO,eAAe,KAAK,GAAI;GACvD;EACF,CAAC;EACD,GAAG;EACH,QAAQ,GAAG,cAAc,GAAG,KAAK,GAAG,IAAI,SAAS,aAAa;CAChE;AACF;;;;;;;AA0BA,MAAa,cAAc,OACzB,QACA,EAAE,OAAO,OAAO,YAAgC,CAAC,MAC9C;CACH,MAAM,QACJ,WACE,WAA0B;EAC1B,QAAQ,OAAO,MAAM,GAAG,KAAK,UAAU,MAAM,EAAE,GAAG;CACpD;CACF,MAAM,QAAQ,UACZ,WAAW,MAAM,OAAO,OACpB,aAAa,QAAQ,aAAa,QAAQ,QAAQ,MAAM,EAAE,IAC1D,KAAA;CACN,MAAM,OACJ,WACA,kBAAkB;EAChB,KAAK;EACL,GAAI,QAAQ,YAAY,KAAA,KAAa,EAAE,SAAS,QAAQ,QAAQ;EAChE,GAAI,QAAQ,QAAQ,KAAA,KAAa,EAAE,KAAK,QAAQ,IAAI;CACtD,CAAC;CACH,IAAI,WAAW,OAAO;CACtB,IAAI,aAAa,KAAA,GAAW,MAAM,IAAI,MAAM,wBAAwB;CACpE,IAAI,UAAU,WAAW;EAAE,GAAG;EAAU,KAAK,CAAC;CAAE,GAAG,QAAQ;CAC3D,IAAI;CACJ,MAAM,cAAc;EAClB,aAAa,KAAK;EAClB,QAAQ,KAAA;EACR,IAAI,QAAQ,SAAS,GAAG,MAAM,OAAO;EACrC,UAAU,CAAC;CACb;CACA,MAAM,WAAW,UAA0B;EACzC,KAAK,MAAM,UAAU,MAAM,OAAO,KAAK,KAAK,CAAC,GAAG;GAC9C,IAAI,OAAO,SAAS,QAAQ,CAAC,QAAS,QAAQ,QAAA,CAAS,OAAO,GAAG;GACjE,QAAQ,KACN,UAAU,QAAQ,QAAS,eAAe,KAAK,KAAK,KAAK,EAAE,CAC7D;EACF;CACF;CACA,MAAM,cAAc,OAAO,gBAAgB;EACzC,MAAM,OAAO,OAAO;EACpB,IAAI,SAAS,KAAA,GAAW;EACxB,QAAQ,KAAK,GAAG,WAAW,UAAW,IAAI,CAAC;EAC3C,WAAW;EACX,QAAQ,IAAI;EACZ,IAAI,QAAQ,SAAS,KAAK,UAAU,KAAA,GAClC,QAAQ,WAAW,OAAO,GAAG;CACjC,CAAC;CACD,QAAQ,QAAQ;CAChB,MAAM;CAEN,MAAM,OACJ,QACA,kBAAkB;EAChB,QAAQ,QAAS;EACjB,MAAM;CACR,GAAG,GAAK;CACV,MAAM,OAAO,OAAO,QAAQ,gBAAgB;CAC5C,IAAI;EACF,MAAM,OAAO,SAAS,cAAc,CAAC;GACnC,KAAK,OAAO,OAAO,QAAQ,IAAI;GAC/B,GAAI,SAAS,KAAA,KAAa,EAAE,KAAK;EACnC,CAAC;CACH,SAAS,OAAO;EACd,cAAc,IAAI;EAClB,aAAa,KAAK;EAClB,YAAY;EACZ,MAAM;CACR;CACA,MAAM,YAAY,kBAAkB;EAClC,OAAY,SAAS,kBAAkB,CAAC,CAAC,CAAC,YAAY,CAAC,CAAC;CAC1D,GAAG,kBAAkB;CACrB,IAAI;CACJ,OAAO,EACL,YACG,aAAa,YAAY;EACxB,cAAc,SAAS;EACvB,cAAc,IAAI;EAClB,YAAY;EACZ,MAAM;EACN,MAAM,OAAO,SAAS,YAAY,CAAC,CAAC,CAAC,YAAY,CAAC,CAAC;CACrD,EAAA,CAAG,EACP;AACF"}
1
+ {"version":3,"file":"stream.js","names":[],"sources":["../src/stream.ts"],"sourcesContent":["import spawn from \"cross-spawn\";\nimport { detectAgentKind } from \"./agents\";\nimport { createBrowserGate } from \"./browser\";\nimport type { AskReason, BrowserGateAction } from \"./browser\";\nimport type { CheckoutClient } from \"./client\";\nimport { formatTerminalQuestion, terminalQuestion } from \"./needs\";\nimport type { TerminalQuestion } from \"./needs\";\nimport {\n AGENT_HEARTBEAT_MS,\n classifyChoiceAnswer,\n parseMultipleAnswer,\n} from \"./protocol\";\nimport type { Checkout } from \"./protocol\";\n\nexport type StreamEvent =\n | { event: \"planning.started\" }\n | { event: \"message.created\"; messageId: string; text: string }\n | {\n event: \"input.answered\";\n inputId: string;\n prompt: string;\n /** The entries of a multiple choice answer, else the answer text. */\n answer: string | string[];\n note?: string;\n /** True when a choice answer is, or a multiple one contains, the user's own text rather than an option. */\n custom?: true;\n }\n | { event: \"input.dismissed\"; inputId: string; prompt: string }\n | { event: \"plan.approved\"; revision: number }\n | { event: \"plan.changes-requested\"; revision: number; feedback: string }\n | { event: \"finished\"; next: string }\n | { event: \"cancelled\"; next: string }\n | { event: \"setup.created\"; products: string[] }\n | {\n event: \"browser.opened\";\n /** The need the tab opened for: an input id, plan or finish. */\n id: string;\n url: string;\n message: string;\n }\n | ({\n event: \"input.needed\";\n id: string;\n reason: AskReason;\n message: string;\n /** The command that answers it, with the answer's shape in angle brackets. */\n answer: string;\n } & TerminalQuestion);\n\nconst STAY_CONNECTED =\n \"This setup is over, not your connection. Keep the stream running, tell the user you are connected and waiting for their next setup, and run wait start.\";\n\nexport const diffEvents = (\n before: Checkout.State,\n after: Checkout.State,\n): StreamEvent[] => {\n const events: StreamEvent[] = [];\n if (before.status === \"waiting\" && after.status === \"planning\") {\n events.push({ event: \"planning.started\" });\n }\n for (const entry of after.log) {\n if (\n entry.role === \"user\" &&\n entry.acknowledgedAt === undefined &&\n !before.log.some((previous) => previous.id === entry.id)\n ) {\n events.push({\n event: \"message.created\",\n messageId: entry.id,\n text: entry.text,\n });\n }\n }\n for (const input of after.inputs) {\n const previous = before.inputs.find(\n (candidate) => candidate.id === input.id,\n );\n if (previous?.status === input.status) continue;\n if (input.status === \"answered\") {\n const answer = input.answer ?? \"\";\n events.push({\n event: \"input.answered\",\n inputId: input.id,\n prompt: input.prompt,\n ...answerFields(input, answer),\n });\n } else if (input.status === \"dismissed\" && after.status !== \"cancelled\") {\n events.push({\n event: \"input.dismissed\",\n inputId: input.id,\n prompt: input.prompt,\n });\n }\n }\n for (const plan of after.plans) {\n const previous = before.plans.find(\n (candidate) => candidate.revision === plan.revision,\n );\n if (previous?.status === plan.status || plan.status === \"proposed\") {\n continue;\n }\n if (plan.status === \"approved\") {\n events.push({ event: \"plan.approved\", revision: plan.revision });\n } else {\n events.push({\n event: \"plan.changes-requested\",\n revision: plan.revision,\n feedback: plan.feedback ?? \"\",\n });\n }\n }\n if (before.status !== \"done\" && after.status === \"done\") {\n events.push({ event: \"finished\", next: STAY_CONNECTED });\n }\n if (before.status !== \"cancelled\" && after.status === \"cancelled\") {\n events.push({ event: \"cancelled\", next: STAY_CONNECTED });\n }\n if (after.id !== null && after.id !== before.id) {\n events.push({\n event: \"setup.created\",\n products: after.products.map((product) => product.slug),\n });\n }\n return events;\n};\n\nexport const answerFields = (input: Checkout.Input, answer: string) => ({\n answer: (input.multiple && parseMultipleAnswer(answer)) || answer,\n ...(input.note !== undefined && { note: input.note }),\n ...(input.kind === \"choice\" &&\n classifyChoiceAnswer(input, answer) === \"custom\" && {\n custom: true as const,\n }),\n});\n\n/** The setup page that joins a link; the link rides in the fragment, which never reaches a server. */\nexport const setupPageUrl = (\n setupAppUrl: string,\n linkId: string,\n setupId: string,\n) => `${setupAppUrl.replace(/\\/$/, \"\")}/#link=${linkId}&setup=${setupId}`;\n\n/**\n * Opens `url` in the user's default browser without waiting for it.\n * `SETUP_AGENT_BROWSER` names another program to run with the URL instead,\n * such as a test driver.\n */\nconst openUrl = (url: string) => {\n const custom = process.env.SETUP_AGENT_BROWSER?.trim();\n const [command, args] = custom\n ? [custom, [url]]\n : process.platform === \"darwin\"\n ? [\"open\", [url]]\n : process.platform === \"win32\"\n ? [\"rundll32\", [\"url.dll,FileProtocolHandler\", url]]\n : [\"xdg-open\", [url]];\n const child = spawn(command, args, { detached: true, stdio: \"ignore\" });\n child.on(\"error\", () => {});\n child.unref();\n};\n\n/** `value` as one shell word, quoted only when it holds more than plain URL characters. */\nexport const shellWord = (value: string) =>\n /^[A-Za-z0-9._~%/:@=+,-]+$/.test(value)\n ? value\n : `'${value.replaceAll(\"'\", `'\\\\''`)}'`;\n\nconst ASK_MESSAGES: Record<\n AskReason,\n (\n question: string,\n context: { agoSeconds: number; page: string; wait: string },\n ) => string\n> = {\n \"recently-opened\": (question, { agoSeconds, wait }) =>\n `A browser tab for setup was opened ${agoSeconds}s ago. Wait for the user there${wait}, or ask the user directly in the terminal: ${question}`,\n \"browser-closed\": (question) =>\n `The user closed the setup tab. Ask the user directly in the terminal: ${question}`,\n \"no-browser\": (question, { page }) =>\n `No browser tab is open for this setup. Ask the user directly in the terminal, or give them ${page}: ${question}`,\n};\n\n/** The command that blocks on a need, beside the one that answers it: `<cmd> <url> wait`. */\nconst waitCommandFor = (answerCommand: string) =>\n answerCommand.endsWith(\" answer\")\n ? `${answerCommand.slice(0, -\" answer\".length)} wait`\n : undefined;\n\n/** What the agent reads when setup opened the browser, or when it should ask the user itself. */\nconst gateEvent = (\n action: BrowserGateAction,\n answerCommand: string,\n page: string,\n waitCommand?: string,\n): StreamEvent => {\n const { need } = action;\n // Closing the setup is the user's call after \"done\"; there is nothing to block on.\n const wait =\n waitCommand !== undefined && need.kind !== \"finish\"\n ? ` with \"${waitCommand} ${need.id}\"`\n : \"\";\n if (action.type === \"open\")\n return {\n event: \"browser.opened\",\n id: need.id,\n url: action.url,\n message: `Opened the setup in the user's browser for ${need.kind === \"input\" ? `\"${need.input.prompt.trim() || \"Your agent needs an answer.\"}\"` : need.kind === \"plan\" ? \"the plan review\" : \"closing the setup\"}. Tell the user once that it is waiting there, and give them ${action.url} in case it did not open.${need.kind === \"finish\" ? \" The answer arrives on this stream.\" : ` Then keep working in the same turn; when you need the answer, block on it${wait || ' with \"wait\"'}. Do not end your turn to wait: nothing on this stream wakes you.`}`,\n };\n const question = terminalQuestion(need);\n return {\n event: \"input.needed\",\n id: need.id,\n reason: action.reason,\n message: ASK_MESSAGES[action.reason](formatTerminalQuestion(question), {\n agoSeconds: Math.round((action.openedAgoMs ?? 0) / 1000),\n page,\n wait,\n }),\n ...question,\n answer: `${answerCommand} ${need.id} <${question.answerFormat}>`,\n };\n};\n\nexport type FollowSetupOptions = {\n /** Writes one line of events; the default prints a JSON array to stdout. */\n print?: (events: StreamEvent[]) => void;\n /** The agent the stream reports in its hello; detected by default. */\n agent?: { cwd?: string; kind?: string };\n /** Opens the setup page when the setup waits on the user; without it, the stream never opens one. */\n browser?: {\n setupAppUrl: string;\n linkId: string;\n /** The command that answers a need, before the need id: `npx assistant-ui@latest setup <url> answer`. */\n answerCommand: string;\n open?: (url: string) => void;\n /** False for `--no-open`: the agent is told to ask instead. */\n canOpen?: boolean;\n now?: () => number;\n };\n};\n\n/**\n * Follows a setup as the agent: says hello, keeps the agent present with\n * heartbeats, prints what changed as stream events, and opens the browser\n * only when the setup waits on the user. Resolves with `stop`, which says\n * goodbye; the caller disposes the client.\n */\nexport const followSetup = async (\n client: Pick<CheckoutClient, \"state\" | \"subscribe\" | \"commands\">,\n { print, agent, browser }: FollowSetupOptions = {},\n) => {\n const write =\n print ??\n ((events: StreamEvent[]) => {\n process.stdout.write(`${JSON.stringify(events)}\\n`);\n });\n const page = (state: Checkout.State) =>\n browser && state.id !== null\n ? setupPageUrl(browser.setupAppUrl, browser.linkId, state.id)\n : undefined;\n const gate =\n browser &&\n createBrowserGate({\n url: page,\n ...(browser.canOpen !== undefined && { canOpen: browser.canOpen }),\n ...(browser.now !== undefined && { now: browser.now }),\n });\n let previous = client.state;\n if (previous === undefined) throw new Error(\"the setup has no state\");\n let pending = diffEvents({ ...previous, log: [] }, previous);\n let timer: ReturnType<typeof setTimeout> | undefined;\n const flush = () => {\n clearTimeout(timer);\n timer = undefined;\n if (pending.length > 0) write(pending);\n pending = [];\n };\n const runGate = (state: Checkout.State) => {\n for (const action of gate?.update(state) ?? []) {\n if (action.type === \"open\") (browser!.open ?? openUrl)(action.url);\n pending.push(\n gateEvent(\n action,\n browser!.answerCommand,\n page(state) ?? \"\",\n waitCommandFor(browser!.answerCommand),\n ),\n );\n }\n };\n const unsubscribe = client.subscribe(() => {\n const next = client.state;\n if (next === undefined) return;\n pending.push(...diffEvents(previous!, next));\n previous = next;\n runGate(next);\n if (pending.length > 0 && timer === undefined)\n timer = setTimeout(flush, 200);\n });\n runGate(previous);\n flush();\n // Presence lapses without a state change, so the gate also looks every second.\n const tick =\n gate &&\n setInterval(() => {\n runGate(previous!);\n flush();\n }, 1_000);\n const kind = agent?.kind ?? detectAgentKind();\n try {\n await client.commands[\"agent/hello\"]({\n cwd: agent?.cwd ?? process.cwd(),\n ...(kind !== undefined && { kind }),\n });\n } catch (error) {\n clearInterval(tick);\n clearTimeout(timer);\n unsubscribe();\n throw error;\n }\n const heartbeat = setInterval(() => {\n void client.commands[\"agent/heartbeat\"]().catch(() => {});\n }, AGENT_HEARTBEAT_MS);\n let stopped: Promise<void> | undefined;\n return {\n stop: () =>\n (stopped ??= (async () => {\n clearInterval(heartbeat);\n clearInterval(tick);\n unsubscribe();\n flush();\n await client.commands[\"agent/bye\"]().catch(() => {});\n })()),\n };\n};\n"],"mappings":";;;;;;AAiDA,MAAM,iBACJ;AAEF,MAAa,cACX,QACA,UACkB;CAClB,MAAM,SAAwB,CAAC;CAC/B,IAAI,OAAO,WAAW,aAAa,MAAM,WAAW,YAClD,OAAO,KAAK,EAAE,OAAO,mBAAmB,CAAC;CAE3C,KAAK,MAAM,SAAS,MAAM,KACxB,IACE,MAAM,SAAS,UACf,MAAM,mBAAmB,KAAA,KACzB,CAAC,OAAO,IAAI,MAAM,aAAa,SAAS,OAAO,MAAM,EAAE,GAEvD,OAAO,KAAK;EACV,OAAO;EACP,WAAW,MAAM;EACjB,MAAM,MAAM;CACd,CAAC;CAGL,KAAK,MAAM,SAAS,MAAM,QAAQ;EAIhC,IAHiB,OAAO,OAAO,MAC5B,cAAc,UAAU,OAAO,MAAM,EAE7B,CAAC,EAAE,WAAW,MAAM,QAAQ;EACvC,IAAI,MAAM,WAAW,YAAY;GAC/B,MAAM,SAAS,MAAM,UAAU;GAC/B,OAAO,KAAK;IACV,OAAO;IACP,SAAS,MAAM;IACf,QAAQ,MAAM;IACd,GAAG,aAAa,OAAO,MAAM;GAC/B,CAAC;EACH,OAAO,IAAI,MAAM,WAAW,eAAe,MAAM,WAAW,aAC1D,OAAO,KAAK;GACV,OAAO;GACP,SAAS,MAAM;GACf,QAAQ,MAAM;EAChB,CAAC;CAEL;CACA,KAAK,MAAM,QAAQ,MAAM,OAAO;EAI9B,IAHiB,OAAO,MAAM,MAC3B,cAAc,UAAU,aAAa,KAAK,QAElC,CAAC,EAAE,WAAW,KAAK,UAAU,KAAK,WAAW,YACtD;EAEF,IAAI,KAAK,WAAW,YAClB,OAAO,KAAK;GAAE,OAAO;GAAiB,UAAU,KAAK;EAAS,CAAC;OAE/D,OAAO,KAAK;GACV,OAAO;GACP,UAAU,KAAK;GACf,UAAU,KAAK,YAAY;EAC7B,CAAC;CAEL;CACA,IAAI,OAAO,WAAW,UAAU,MAAM,WAAW,QAC/C,OAAO,KAAK;EAAE,OAAO;EAAY,MAAM;CAAe,CAAC;CAEzD,IAAI,OAAO,WAAW,eAAe,MAAM,WAAW,aACpD,OAAO,KAAK;EAAE,OAAO;EAAa,MAAM;CAAe,CAAC;CAE1D,IAAI,MAAM,OAAO,QAAQ,MAAM,OAAO,OAAO,IAC3C,OAAO,KAAK;EACV,OAAO;EACP,UAAU,MAAM,SAAS,KAAK,YAAY,QAAQ,IAAI;CACxD,CAAC;CAEH,OAAO;AACT;AAEA,MAAa,gBAAgB,OAAuB,YAAoB;CACtE,QAAS,MAAM,YAAY,oBAAoB,MAAM,KAAM;CAC3D,GAAI,MAAM,SAAS,KAAA,KAAa,EAAE,MAAM,MAAM,KAAK;CACnD,GAAI,MAAM,SAAS,YACjB,qBAAqB,OAAO,MAAM,MAAM,YAAY,EAClD,QAAQ,KACV;AACJ;;AAGA,MAAa,gBACX,aACA,QACA,YACG,GAAG,YAAY,QAAQ,OAAO,EAAE,EAAE,SAAS,OAAO,SAAS;;;;;;AAOhE,MAAM,WAAW,QAAgB;CAC/B,MAAM,SAAS,QAAQ,IAAI,qBAAqB,KAAK;CACrD,MAAM,CAAC,SAAS,QAAQ,SACpB,CAAC,QAAQ,CAAC,GAAG,CAAC,IACd,QAAQ,aAAa,WACnB,CAAC,QAAQ,CAAC,GAAG,CAAC,IACd,QAAQ,aAAa,UACnB,CAAC,YAAY,CAAC,+BAA+B,GAAG,CAAC,IACjD,CAAC,YAAY,CAAC,GAAG,CAAC;CAC1B,MAAM,QAAQ,MAAM,SAAS,MAAM;EAAE,UAAU;EAAM,OAAO;CAAS,CAAC;CACtE,MAAM,GAAG,eAAe,CAAC,CAAC;CAC1B,MAAM,MAAM;AACd;;AAGA,MAAa,aAAa,UACxB,4BAA4B,KAAK,KAAK,IAClC,QACA,IAAI,MAAM,WAAW,KAAK,OAAO,EAAE;AAEzC,MAAM,eAMF;CACF,oBAAoB,UAAU,EAAE,YAAY,WAC1C,sCAAsC,WAAW,gCAAgC,KAAK,8CAA8C;CACtI,mBAAmB,aACjB,yEAAyE;CAC3E,eAAe,UAAU,EAAE,WACzB,8FAA8F,KAAK,IAAI;AAC3G;;AAGA,MAAM,kBAAkB,kBACtB,cAAc,SAAS,SAAS,IAC5B,GAAG,cAAc,MAAM,GAAG,EAAiB,EAAE,SAC7C,KAAA;;AAGN,MAAM,aACJ,QACA,eACA,MACA,gBACgB;CAChB,MAAM,EAAE,SAAS;CAEjB,MAAM,OACJ,gBAAgB,KAAA,KAAa,KAAK,SAAS,WACvC,UAAU,YAAY,GAAG,KAAK,GAAG,KACjC;CACN,IAAI,OAAO,SAAS,QAClB,OAAO;EACL,OAAO;EACP,IAAI,KAAK;EACT,KAAK,OAAO;EACZ,SAAS,8CAA8C,KAAK,SAAS,UAAU,IAAI,KAAK,MAAM,OAAO,KAAK,KAAK,8BAA8B,KAAK,KAAK,SAAS,SAAS,oBAAoB,oBAAoB,+DAA+D,OAAO,IAAI,2BAA2B,KAAK,SAAS,WAAW,wCAAwC,6EAA6E,QAAQ,iBAAe;CAC7d;CACF,MAAM,WAAW,iBAAiB,IAAI;CACtC,OAAO;EACL,OAAO;EACP,IAAI,KAAK;EACT,QAAQ,OAAO;EACf,SAAS,aAAa,OAAO,OAAO,CAAC,uBAAuB,QAAQ,GAAG;GACrE,YAAY,KAAK,OAAO,OAAO,eAAe,KAAK,GAAI;GACvD;GACA;EACF,CAAC;EACD,GAAG;EACH,QAAQ,GAAG,cAAc,GAAG,KAAK,GAAG,IAAI,SAAS,aAAa;CAChE;AACF;;;;;;;AA0BA,MAAa,cAAc,OACzB,QACA,EAAE,OAAO,OAAO,YAAgC,CAAC,MAC9C;CACH,MAAM,QACJ,WACE,WAA0B;EAC1B,QAAQ,OAAO,MAAM,GAAG,KAAK,UAAU,MAAM,EAAE,GAAG;CACpD;CACF,MAAM,QAAQ,UACZ,WAAW,MAAM,OAAO,OACpB,aAAa,QAAQ,aAAa,QAAQ,QAAQ,MAAM,EAAE,IAC1D,KAAA;CACN,MAAM,OACJ,WACA,kBAAkB;EAChB,KAAK;EACL,GAAI,QAAQ,YAAY,KAAA,KAAa,EAAE,SAAS,QAAQ,QAAQ;EAChE,GAAI,QAAQ,QAAQ,KAAA,KAAa,EAAE,KAAK,QAAQ,IAAI;CACtD,CAAC;CACH,IAAI,WAAW,OAAO;CACtB,IAAI,aAAa,KAAA,GAAW,MAAM,IAAI,MAAM,wBAAwB;CACpE,IAAI,UAAU,WAAW;EAAE,GAAG;EAAU,KAAK,CAAC;CAAE,GAAG,QAAQ;CAC3D,IAAI;CACJ,MAAM,cAAc;EAClB,aAAa,KAAK;EAClB,QAAQ,KAAA;EACR,IAAI,QAAQ,SAAS,GAAG,MAAM,OAAO;EACrC,UAAU,CAAC;CACb;CACA,MAAM,WAAW,UAA0B;EACzC,KAAK,MAAM,UAAU,MAAM,OAAO,KAAK,KAAK,CAAC,GAAG;GAC9C,IAAI,OAAO,SAAS,QAAQ,CAAC,QAAS,QAAQ,QAAA,CAAS,OAAO,GAAG;GACjE,QAAQ,KACN,UACE,QACA,QAAS,eACT,KAAK,KAAK,KAAK,IACf,eAAe,QAAS,aAAa,CACvC,CACF;EACF;CACF;CACA,MAAM,cAAc,OAAO,gBAAgB;EACzC,MAAM,OAAO,OAAO;EACpB,IAAI,SAAS,KAAA,GAAW;EACxB,QAAQ,KAAK,GAAG,WAAW,UAAW,IAAI,CAAC;EAC3C,WAAW;EACX,QAAQ,IAAI;EACZ,IAAI,QAAQ,SAAS,KAAK,UAAU,KAAA,GAClC,QAAQ,WAAW,OAAO,GAAG;CACjC,CAAC;CACD,QAAQ,QAAQ;CAChB,MAAM;CAEN,MAAM,OACJ,QACA,kBAAkB;EAChB,QAAQ,QAAS;EACjB,MAAM;CACR,GAAG,GAAK;CACV,MAAM,OAAO,OAAO,QAAQ,gBAAgB;CAC5C,IAAI;EACF,MAAM,OAAO,SAAS,cAAc,CAAC;GACnC,KAAK,OAAO,OAAO,QAAQ,IAAI;GAC/B,GAAI,SAAS,KAAA,KAAa,EAAE,KAAK;EACnC,CAAC;CACH,SAAS,OAAO;EACd,cAAc,IAAI;EAClB,aAAa,KAAK;EAClB,YAAY;EACZ,MAAM;CACR;CACA,MAAM,YAAY,kBAAkB;EAClC,OAAY,SAAS,kBAAkB,CAAC,CAAC,CAAC,YAAY,CAAC,CAAC;CAC1D,GAAG,kBAAkB;CACrB,IAAI;CACJ,OAAO,EACL,YACG,aAAa,YAAY;EACxB,cAAc,SAAS;EACvB,cAAc,IAAI;EAClB,YAAY;EACZ,MAAM;EACN,MAAM,OAAO,SAAS,YAAY,CAAC,CAAC,CAAC,YAAY,CAAC,CAAC;CACrD,EAAA,CAAG,EACP;AACF"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "setup-agent",
3
- "version": "0.1.0",
3
+ "version": "0.1.2",
4
4
  "description": "A live setup shared between a browser and the coding agent installing the products in it, on Statewire",
5
5
  "license": "MIT",
6
6
  "homepage": "https://www.assistant-ui.com/",
@@ -51,7 +51,7 @@
51
51
  "statewire": "^0.22.1"
52
52
  },
53
53
  "peerDependencies": {
54
- "@assistant-ui/tap": "^0.9.25"
54
+ "@assistant-ui/tap": "^0.9.26"
55
55
  },
56
56
  "peerDependenciesMeta": {
57
57
  "@assistant-ui/tap": {
@@ -59,8 +59,8 @@
59
59
  }
60
60
  },
61
61
  "devDependencies": {
62
- "@assistant-ui/tap": "0.9.25",
63
- "@assistant-ui/x-buildutils": "0.0.32",
62
+ "@assistant-ui/tap": "0.9.26",
63
+ "@assistant-ui/x-buildutils": "0.0.33",
64
64
  "@types/cross-spawn": "^6.0.6",
65
65
  "@types/node": "^26.6.5",
66
66
  "@types/react": "^19.3.0",
package/src/cli.test.ts CHANGED
@@ -59,6 +59,146 @@ describe("the agent's briefing", () => {
59
59
  });
60
60
  });
61
61
 
62
+ describe("running to the end", () => {
63
+ it("tells the agent not to end its turn to wait, and how to block instead", () => {
64
+ for (const instructions of [
65
+ agentInstructions("https://example.test/session"),
66
+ agentInstructions("https://example.test/session", {
67
+ command: "npx assistant-ui@latest setup",
68
+ startedByAgent: { browserUrl: "https://setup.test", streaming: true },
69
+ }),
70
+ ]) {
71
+ expect(instructions).toContain("Run the setup to the end in one go.");
72
+ expect(instructions).toContain(
73
+ "never end your turn to wait for an answer",
74
+ );
75
+ expect(instructions).toMatch(/ wait <input-id>\n/);
76
+ expect(instructions).toContain('run its "next" command, right away');
77
+ expect(instructions).toContain('never repeat an "ask" or "plan"');
78
+ expect(instructions).not.toContain(
79
+ 'block with "wait <input-id>" only when nothing else can proceed',
80
+ );
81
+ }
82
+ const streaming = agentInstructions("https://example.test/session", {
83
+ startedByAgent: { browserUrl: "https://setup.test", streaming: true },
84
+ });
85
+ expect(streaming).toContain("New output does not wake you");
86
+ expect(streaming).not.toContain('wait for "input.answered"');
87
+ });
88
+ });
89
+
90
+ describe("waiting on the user", () => {
91
+ // Under the two minutes Claude Code's shell gives a command by default.
92
+ const DEFAULT_WAIT_SECONDS = 100;
93
+ const URL = "https://checkout.test/session";
94
+
95
+ const connect = () => {
96
+ const listeners = new Set<() => void>();
97
+ const state: Checkout.State = {
98
+ ...initialCheckoutState(),
99
+ id: "setup-a",
100
+ createdAt: 1,
101
+ status: "planning",
102
+ inputs: [
103
+ {
104
+ id: "q1",
105
+ phase: "planning",
106
+ kind: "text",
107
+ prompt: "Which project?",
108
+ optional: false,
109
+ status: "open",
110
+ createdAt: 2,
111
+ },
112
+ ],
113
+ };
114
+ const client = {
115
+ state,
116
+ subscribe: (listener: () => void) => {
117
+ listeners.add(listener);
118
+ return () => listeners.delete(listener);
119
+ },
120
+ commands: {},
121
+ dispose: vi.fn(),
122
+ };
123
+ connectCheckoutMock.mockResolvedValue(
124
+ client as unknown as Awaited<ReturnType<typeof connectCheckout>>,
125
+ );
126
+ const stdout = vi.spyOn(process.stdout, "write").mockReturnValue(true);
127
+ vi.useFakeTimers();
128
+ onTestFinished(() => {
129
+ vi.useRealTimers();
130
+ stdout.mockRestore();
131
+ connectCheckoutMock.mockReset();
132
+ });
133
+ const printed = () =>
134
+ JSON.parse(String(stdout.mock.lastCall?.[0] ?? "null")) as unknown;
135
+ const answer = (value: string) => {
136
+ state.inputs[0]!.status = "answered";
137
+ state.inputs[0]!.answer = value;
138
+ for (const listener of listeners) listener();
139
+ };
140
+ return { state, printed, answer };
141
+ };
142
+
143
+ it("hands the turn back with the command to run again before an agent shell kills the wait", async () => {
144
+ const t = connect();
145
+ const run = main([URL, "wait", "q1"]);
146
+ await vi.advanceTimersByTimeAsync(DEFAULT_WAIT_SECONDS * 1000 - 1);
147
+ expect(t.printed()).toBeNull();
148
+ await vi.advanceTimersByTimeAsync(1);
149
+ await run;
150
+ expect(t.printed()).toMatchObject({
151
+ ok: false,
152
+ status: "waiting",
153
+ waitingFor: "q1",
154
+ next: `npx setup-agent ${URL} wait q1`,
155
+ });
156
+ });
157
+
158
+ it("hands back a plan wait as wait plan, so the agent does not submit the plan again", async () => {
159
+ const t = connect();
160
+ t.state.plans.push({
161
+ revision: 1,
162
+ markdown: "## Steps",
163
+ status: "proposed",
164
+ submittedAt: 3,
165
+ });
166
+ const run = main([URL, "wait", "plan"]);
167
+ await vi.advanceTimersByTimeAsync(DEFAULT_WAIT_SECONDS * 1000);
168
+ await run;
169
+ expect(t.printed()).toMatchObject({
170
+ ok: false,
171
+ status: "waiting",
172
+ waitingFor: "plan",
173
+ next: `npx setup-agent ${URL} wait plan`,
174
+ });
175
+ });
176
+
177
+ it("prints the answer when it arrives in time", async () => {
178
+ const t = connect();
179
+ const run = main([URL, "wait", "q1"]);
180
+ await vi.advanceTimersByTimeAsync(5_000);
181
+ t.answer("apps/web");
182
+ await run;
183
+ expect(t.printed()).toMatchObject({
184
+ ok: true,
185
+ inputId: "q1",
186
+ status: "answered",
187
+ answer: "apps/web",
188
+ });
189
+ });
190
+
191
+ it("waits as long as it takes with --timeout 0", async () => {
192
+ const t = connect();
193
+ const run = main([URL, "wait", "q1", "--timeout", "0"]);
194
+ await vi.advanceTimersByTimeAsync(DEFAULT_WAIT_SECONDS * 1000 * 5);
195
+ expect(t.printed()).toBeNull();
196
+ t.answer("apps/web");
197
+ await run;
198
+ expect(t.printed()).toMatchObject({ ok: true, answer: "apps/web" });
199
+ });
200
+ });
201
+
62
202
  describe("askSeed", () => {
63
203
  const parse = (argv: string[]) => {
64
204
  const flags = new Map<string, string | true>();