assistant-ui 0.0.120 → 0.0.122

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 (133) hide show
  1. package/README.md +60 -1
  2. package/dist/commands/add.d.ts.map +1 -1
  3. package/dist/commands/add.js +1 -2
  4. package/dist/commands/add.js.map +1 -1
  5. package/dist/commands/cloud.d.ts +25 -0
  6. package/dist/commands/cloud.d.ts.map +1 -0
  7. package/dist/commands/cloud.js +194 -0
  8. package/dist/commands/cloud.js.map +1 -0
  9. package/dist/commands/create.d.ts.map +1 -1
  10. package/dist/commands/create.js +10 -2
  11. package/dist/commands/create.js.map +1 -1
  12. package/dist/commands/info.js +2 -2
  13. package/dist/commands/init.d.ts.map +1 -1
  14. package/dist/commands/init.js +1 -2
  15. package/dist/commands/init.js.map +1 -1
  16. package/dist/commands/mcp.d.ts.map +1 -1
  17. package/dist/commands/mcp.js +95 -23
  18. package/dist/commands/mcp.js.map +1 -1
  19. package/dist/lib/agent-skill.d.ts +2 -2
  20. package/dist/lib/agent-skill.d.ts.map +1 -1
  21. package/dist/lib/agent-skill.js +10 -28
  22. package/dist/lib/agent-skill.js.map +1 -1
  23. package/dist/lib/cloud-abort.d.ts +2 -0
  24. package/dist/lib/cloud-abort.d.ts.map +1 -0
  25. package/dist/lib/cloud-abort.js +13 -0
  26. package/dist/lib/cloud-abort.js.map +1 -0
  27. package/dist/lib/cloud-auth.d.ts +28 -0
  28. package/dist/lib/cloud-auth.d.ts.map +1 -0
  29. package/dist/lib/cloud-auth.js +169 -0
  30. package/dist/lib/cloud-auth.js.map +1 -0
  31. package/dist/lib/cloud-config.d.ts +21 -0
  32. package/dist/lib/cloud-config.d.ts.map +1 -0
  33. package/dist/lib/cloud-config.js +76 -0
  34. package/dist/lib/cloud-config.js.map +1 -0
  35. package/dist/lib/cloud-provision.d.ts +20 -0
  36. package/dist/lib/cloud-provision.d.ts.map +1 -0
  37. package/dist/lib/cloud-provision.js +55 -0
  38. package/dist/lib/cloud-provision.js.map +1 -0
  39. package/dist/lib/cloud-setup-login.d.ts +9 -0
  40. package/dist/lib/cloud-setup-login.d.ts.map +1 -0
  41. package/dist/lib/cloud-setup-login.js +137 -0
  42. package/dist/lib/cloud-setup-login.js.map +1 -0
  43. package/dist/lib/cloud-url.d.ts +2 -0
  44. package/dist/lib/cloud-url.d.ts.map +1 -0
  45. package/dist/lib/cloud-url.js +14 -0
  46. package/dist/lib/cloud-url.js.map +1 -0
  47. package/dist/lib/create-project.d.ts +0 -9
  48. package/dist/lib/create-project.d.ts.map +1 -1
  49. package/dist/lib/create-project.js +15 -46
  50. package/dist/lib/create-project.js.map +1 -1
  51. package/dist/lib/transform.d.ts +0 -4
  52. package/dist/lib/transform.d.ts.map +1 -1
  53. package/dist/lib/transform.js +8 -17
  54. package/dist/lib/transform.js.map +1 -1
  55. package/dist/lib/utils/download.d.ts +5 -0
  56. package/dist/lib/utils/download.d.ts.map +1 -0
  57. package/dist/lib/utils/download.js +41 -0
  58. package/dist/lib/utils/download.js.map +1 -0
  59. package/dist/lib/utils/file-scanner.d.ts +0 -1
  60. package/dist/lib/utils/file-scanner.d.ts.map +1 -1
  61. package/dist/lib/utils/file-scanner.js +1 -16
  62. package/dist/lib/utils/file-scanner.js.map +1 -1
  63. package/dist/lib/utils/package-manager.d.ts +7 -0
  64. package/dist/lib/utils/package-manager.d.ts.map +1 -1
  65. package/dist/lib/utils/package-manager.js +15 -1
  66. package/dist/lib/utils/package-manager.js.map +1 -1
  67. package/dist/program.d.ts.map +1 -1
  68. package/dist/program.js +2 -1
  69. package/dist/program.js.map +1 -1
  70. package/package.json +12 -8
  71. package/src/commands/add.ts +2 -1
  72. package/src/commands/cloud.test.ts +238 -0
  73. package/src/commands/cloud.ts +455 -0
  74. package/src/commands/create.ts +13 -3
  75. package/src/commands/init.ts +5 -2
  76. package/src/commands/mcp.ts +223 -56
  77. package/src/lib/agent-skill.ts +18 -44
  78. package/src/lib/cloud-abort.ts +12 -0
  79. package/src/lib/cloud-auth.test.ts +500 -0
  80. package/src/lib/cloud-auth.ts +273 -0
  81. package/src/lib/cloud-config.test.ts +82 -0
  82. package/src/lib/cloud-config.ts +138 -0
  83. package/src/lib/cloud-provision.test.ts +132 -0
  84. package/src/lib/cloud-provision.ts +93 -0
  85. package/src/lib/cloud-setup-login.test.ts +361 -0
  86. package/src/lib/cloud-setup-login.ts +240 -0
  87. package/src/lib/cloud-url.ts +19 -0
  88. package/src/lib/create-project.test.ts +0 -17
  89. package/src/lib/create-project.ts +33 -98
  90. package/src/lib/transform-files.test.ts +1 -3
  91. package/src/lib/transform.ts +6 -20
  92. package/src/lib/utils/download.ts +57 -0
  93. package/src/lib/utils/file-scanner.ts +0 -26
  94. package/src/lib/utils/package-manager.ts +26 -0
  95. package/src/lib/utils/registry.test.ts +0 -6
  96. package/src/program.ts +2 -0
  97. package/templates/cloud-harness/.assistant-ui/template.json +3 -0
  98. package/templates/cloud-harness/.env.example +1 -0
  99. package/templates/cloud-harness/.gitignore +42 -0
  100. package/templates/cloud-harness/README.md +28 -0
  101. package/templates/cloud-harness/app/api/chat/route.ts +14 -0
  102. package/templates/cloud-harness/app/api/credential/route.ts +14 -0
  103. package/templates/cloud-harness/app/assistant.tsx +83 -0
  104. package/templates/cloud-harness/app/favicon.ico +0 -0
  105. package/templates/cloud-harness/app/globals.css +139 -0
  106. package/templates/cloud-harness/app/layout.tsx +37 -0
  107. package/templates/cloud-harness/app/page.tsx +5 -0
  108. package/templates/cloud-harness/components/assistant-ui/elements/attachment.aui.tsx +279 -0
  109. package/templates/cloud-harness/components/assistant-ui/elements/collapsible-root.tsx +19 -0
  110. package/templates/cloud-harness/components/assistant-ui/elements/markdown-text.tsx +238 -0
  111. package/templates/cloud-harness/components/assistant-ui/elements/thread.aui.tsx +521 -0
  112. package/templates/cloud-harness/components/assistant-ui/elements/tool-fallback.aui.tsx +1321 -0
  113. package/templates/cloud-harness/components/assistant-ui/elements/tooltip-icon-button.tsx +49 -0
  114. package/templates/cloud-harness/components/ui/avatar.tsx +109 -0
  115. package/templates/cloud-harness/components/ui/button.tsx +58 -0
  116. package/templates/cloud-harness/components/ui/collapsible.tsx +21 -0
  117. package/templates/cloud-harness/components/ui/dialog.tsx +159 -0
  118. package/templates/cloud-harness/components/ui/textarea.tsx +18 -0
  119. package/templates/cloud-harness/components/ui/tooltip.tsx +69 -0
  120. package/templates/cloud-harness/components.json +24 -0
  121. package/templates/cloud-harness/hooks/use-attachment-src.ts +46 -0
  122. package/templates/cloud-harness/hooks/use-copy-to-clipboard.ts +54 -0
  123. package/templates/cloud-harness/lib/utils.ts +1 -0
  124. package/templates/cloud-harness/next.config.ts +6 -0
  125. package/templates/cloud-harness/package.json +51 -0
  126. package/templates/cloud-harness/postcss.config.mjs +5 -0
  127. package/templates/cloud-harness/tsconfig.json +33 -0
  128. package/templates/cloud-harness/vendor/README.md +13 -0
  129. package/templates/cloud-harness/vendor/assistant-ui-react-harness-sdk-0.0.2.tgz +0 -0
  130. package/templates/cloud-harness/vendor/harness-sdk-0.3.1.tgz +0 -0
  131. package/templates/cloud-harness/vendor/provenance.json +38 -0
  132. package/templates/cloud-harness/vendor/statewire-0.19.3.tgz +0 -0
  133. /package/{LICENSE → templates/cloud-harness/vendor/LICENSE} +0 -0
package/README.md CHANGED
@@ -58,7 +58,66 @@ npx assistant-ui info
58
58
 
59
59
  ## Templates
60
60
 
61
- `create` scaffolds from named templates: `default` (AI SDK), `minimal`, `cloud`, `cloud-clerk`, `langchain`, `mcp`, `eve`. Pass `-t <name>`, pass `--example <name>` for examples such as `with-ai-sdk-v7`, use `--native` for Expo / React Native, use `--ink` for React Ink, or pass `--preset <url>` to scaffold from an `assistant-ui.com` playground link.
61
+ `create` scaffolds from named templates: `default` (AI SDK), `minimal`, `cloud`, `cloud-clerk`, `cloud-harness`, `langchain`, `mcp`, `eve`. Pass `-t <name>`, pass `--example <name>` for examples such as `with-ai-sdk-v7`, use `--native` for Expo / React Native, use `--ink` for React Ink, or pass `--preset <url>` to scaffold from an `assistant-ui.com` playground link.
62
+
63
+ ## Shared cloud chat
64
+
65
+ ```bash
66
+ npx assistant-ui@latest cloud setup multiplayer-chat
67
+ cd multiplayer-chat
68
+ npm run dev
69
+ ```
70
+
71
+ Setup signs you in through your browser, selects or creates your organization
72
+ and project, provisions a hosted harness, and installs the shared chat starter.
73
+ Add your `OPENAI_API_KEY` to the generated `.env.local` before starting the app.
74
+ Open `http://localhost:3000/#main` in two browsers. Both clients share the
75
+ conversation and see replies as they stream. **Share this chat** copies the
76
+ current conversation's URL.
77
+
78
+ Select resources explicitly for a script or agent:
79
+
80
+ ```bash
81
+ npx assistant-ui@latest cloud setup multiplayer-chat --org team --new-project hackathon-chat --backend-url http://localhost:3000/api/chat --yes
82
+ ```
83
+
84
+ Use `--project <id-or-slug>` for an existing project. A hackathon access code
85
+ can be supplied with `--access-code <code>` or `ASSISTANT_UI_ACCESS_CODE`.
86
+ `--use-npm`, `--use-pnpm`, `--use-yarn`, and `--use-bun` select the installer;
87
+ `--skip-install` leaves dependency installation to you. For a hosted app,
88
+ pass its HTTPS chat endpoint as `--backend-url` during initial setup. If you
89
+ deploy a chat first configured locally, update its backend allowlist in the
90
+ Cloud dashboard and its `backendUrl` in `.assistant-ui/cloud.json`, then rerun
91
+ setup with the same HTTPS `--backend-url`. Existing conversations keep their
92
+ original backend; open the deployed app with a fresh thread fragment such as
93
+ `#deployed-chat`, then use **Share this chat**.
94
+
95
+ The project API key stays in `.env.local`, with owner-only permissions and a
96
+ Git ignore entry. `.assistant-ui/cloud.json` stores the selected project and
97
+ harness IDs. Browser clients receive short-lived credentials from the app's
98
+ server and share the `hackathon` user. Add your application authentication to
99
+ `/api/credential` when the chat needs individual users or private access.
100
+
101
+ Run `npx assistant-ui@latest cloud setup .` from an existing cloud-harness starter to resume
102
+ setup. Existing environment values are preserved; conflicting cloud settings
103
+ produce an error. `npx assistant-ui@latest cloud login` signs in separately and
104
+ `npx assistant-ui@latest cloud logout` revokes the saved CLI login.
105
+
106
+ When an agent is installing from an active setup wizard, pass its setup-agent
107
+ URL with `--setup-url <url>` to `cloud login` or `cloud setup`. The wizard shows
108
+ the device approval code and sends you to Accounts for explicit consent, then
109
+ returns to the same setup. The CLI polls Accounts directly and saves credentials
110
+ locally with owner-only permissions; tokens never pass through the wizard or
111
+ its generic secret inputs. Cancelling the sign-in question or setup cancels
112
+ pending login. Returning from Accounts alone does not complete login.
113
+
114
+ Before the npm patch is released, use the
115
+ [verified wizard sign-in prerelease](https://www.assistant-ui.com/downloads/assistant-ui-wizard-login-ea9aae48e.tgz)
116
+ with your active setup-agent connection URL:
117
+
118
+ ```bash
119
+ npx --yes --package=https://www.assistant-ui.com/downloads/assistant-ui-wizard-login-ea9aae48e.tgz assistant-ui cloud login --setup-url "<active-setup-agent-url>"
120
+ ```
62
121
 
63
122
  ## Documentation
64
123
 
@@ -1 +1 @@
1
- {"version":3,"file":"add.d.ts","sourceRoot":"","sources":["../../src/commands/add.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AAUpC,OAAO,EACL,KAAK,kBAAkB,EAExB,wCAAqC;AAEtC,MAAM,WAAW,iBAAiB;IAChC,OAAO,EAAE,MAAM,CAAC;IAChB,IAAI,EAAE,MAAM,EAAE,CAAC;CAChB;AAED,wBAAgB,uBAAuB,CAAC,MAAM,EAAE;IAC9C,UAAU,EAAE,MAAM,EAAE,CAAC;IACrB,cAAc,EAAE,kBAAkB,CAAC;IACnC,GAAG,CAAC,EAAE,OAAO,CAAC;IACd,SAAS,CAAC,EAAE,OAAO,CAAC;IACpB,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,QAAQ,CAAC,EAAE,KAAK,GAAG,QAAQ,CAAC;CAC7B,GAAG,iBAAiB,CAkBpB;AAED,eAAO,MAAM,GAAG,SA4DZ,CAAC"}
1
+ {"version":3,"file":"add.d.ts","sourceRoot":"","sources":["../../src/commands/add.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AASpC,OAAO,EAGL,KAAK,kBAAkB,EAExB,wCAAqC;AAEtC,MAAM,WAAW,iBAAiB;IAChC,OAAO,EAAE,MAAM,CAAC;IAChB,IAAI,EAAE,MAAM,EAAE,CAAC;CAChB;AAED,wBAAgB,uBAAuB,CAAC,MAAM,EAAE;IAC9C,UAAU,EAAE,MAAM,EAAE,CAAC;IACrB,cAAc,EAAE,kBAAkB,CAAC;IACnC,GAAG,CAAC,EAAE,OAAO,CAAC;IACd,SAAS,CAAC,EAAE,OAAO,CAAC;IACpB,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,QAAQ,CAAC,EAAE,KAAK,GAAG,QAAQ,CAAC;CAC7B,GAAG,iBAAiB,CAkBpB;AAED,eAAO,MAAM,GAAG,SA4DZ,CAAC"}
@@ -2,8 +2,7 @@ import { logger } from "../lib/utils/logger.js";
2
2
  import { hasConfig } from "../lib/utils/config.js";
3
3
  import { detectRegistryPlatform, getComponentsJsonStyle, resolveRegistryItemUrl } from "../lib/utils/registry.js";
4
4
  import { SpawnExitError, SpawnSignalError, runSpawn } from "../lib/run-spawn.js";
5
- import { resolvePackageManagerForCwd } from "../lib/utils/package-manager.js";
6
- import { dlxCommand, resolvePackageManager } from "../lib/create-project.js";
5
+ import { dlxCommand, resolvePackageManager, resolvePackageManagerForCwd } from "../lib/utils/package-manager.js";
7
6
  import { Command } from "commander";
8
7
  //#region src/commands/add.ts
9
8
  function createAddComponentsPlan(params) {
@@ -1 +1 @@
1
- {"version":3,"file":"add.js","names":[],"sources":["../../src/commands/add.ts"],"sourcesContent":["import { Command } from \"commander\";\nimport { logger } from \"../lib/utils/logger\";\nimport { hasConfig } from \"../lib/utils/config\";\nimport {\n detectRegistryPlatform,\n getComponentsJsonStyle,\n resolveRegistryItemUrl,\n} from \"../lib/utils/registry\";\nimport { dlxCommand, resolvePackageManager } from \"../lib/create-project\";\nimport { runSpawn, SpawnExitError, SpawnSignalError } from \"../lib/run-spawn\";\nimport {\n type PackageManagerName,\n resolvePackageManagerForCwd,\n} from \"../lib/utils/package-manager\";\n\nexport interface AddComponentsPlan {\n command: string;\n args: string[];\n}\n\nexport function createAddComponentsPlan(params: {\n components: string[];\n packageManager: PackageManagerName;\n yes?: boolean;\n overwrite?: boolean;\n path?: string;\n style?: string;\n platform?: \"web\" | \"native\";\n}): AddComponentsPlan {\n const componentsToAdd = params.components.map((c) => {\n if (!/^[a-zA-Z0-9-/]+$/.test(c)) {\n throw new Error(`Invalid component name: ${c}`);\n }\n return resolveRegistryItemUrl(c, params.style, params.platform);\n });\n\n const [command, dlxArgs] = dlxCommand(params.packageManager);\n const args = [...dlxArgs, \"shadcn@latest\", \"add\", ...componentsToAdd];\n\n // For npm, dlxArgs may already include `--yes` for npx auto-install.\n // This flag is for shadcn's own confirmation prompt.\n if (params.yes) args.push(\"--yes\");\n if (params.overwrite) args.push(\"--overwrite\");\n if (params.path) args.push(\"--path\", params.path);\n\n return { command, args };\n}\n\nexport const add = new Command()\n .name(\"add\")\n .description(\"add a component to your project\")\n .argument(\"<components...>\", \"the components to add\")\n .option(\"-y, --yes\", \"skip confirmation prompt.\", true)\n .option(\"-o, --overwrite\", \"overwrite existing files.\", false)\n .option(\n \"-c, --cwd <cwd>\",\n \"the working directory. defaults to the current directory.\",\n process.cwd(),\n )\n .option(\"-p, --path <path>\", \"the path to add the component to.\")\n .option(\"--use-npm\", \"explicitly use npm\")\n .option(\"--use-pnpm\", \"explicitly use pnpm\")\n .option(\"--use-yarn\", \"explicitly use yarn\")\n .option(\"--use-bun\", \"explicitly use bun\")\n .action(async (components: string[], opts) => {\n const platform = detectRegistryPlatform(opts.cwd);\n\n // Check if project is initialized\n if (!hasConfig(opts.cwd)) {\n logger.warn(\n `It looks like you haven't initialized your project yet. Defaulting to ${platform === \"native\" ? \"the native component tree\" : \"Base UI flavored components\"}. Run 'assistant-ui init' first for a configured setup.`,\n );\n logger.break();\n }\n\n logger.info(`Using the ${platform} registry tree.`);\n logger.step(`Adding ${components.length} component(s)...`);\n\n const packageManager = await resolvePackageManagerForCwd(\n opts.cwd,\n resolvePackageManager(opts),\n );\n const style =\n platform === \"web\" ? getComponentsJsonStyle(opts.cwd) : undefined;\n const { command, args } = createAddComponentsPlan({\n components,\n packageManager,\n yes: opts.yes,\n overwrite: opts.overwrite,\n path: opts.path,\n ...(style === undefined ? {} : { style }),\n platform,\n });\n\n try {\n await runSpawn(command, args, opts.cwd);\n } catch (error) {\n if (error instanceof SpawnSignalError) throw error;\n if (error instanceof SpawnExitError) {\n logger.error(`Process exited with code ${error.code}`);\n process.exit(error.code);\n }\n const message = error instanceof Error ? error.message : String(error);\n logger.error(`Failed to add components: ${message}`);\n process.exit(1);\n }\n\n logger.success(\"Components added successfully!\");\n });\n"],"mappings":";;;;;;;;AAoBA,SAAgB,wBAAwB,QAQlB;CACpB,MAAM,kBAAkB,OAAO,WAAW,KAAK,MAAM;EACnD,IAAI,CAAC,mBAAmB,KAAK,CAAC,GAC5B,MAAM,IAAI,MAAM,2BAA2B,GAAG;EAEhD,OAAO,uBAAuB,GAAG,OAAO,OAAO,OAAO,QAAQ;CAChE,CAAC;CAED,MAAM,CAAC,SAAS,WAAW,WAAW,OAAO,cAAc;CAC3D,MAAM,OAAO;EAAC,GAAG;EAAS;EAAiB;EAAO,GAAG;CAAe;CAIpE,IAAI,OAAO,KAAK,KAAK,KAAK,OAAO;CACjC,IAAI,OAAO,WAAW,KAAK,KAAK,aAAa;CAC7C,IAAI,OAAO,MAAM,KAAK,KAAK,UAAU,OAAO,IAAI;CAEhD,OAAO;EAAE;EAAS;CAAK;AACzB;AAEA,MAAa,MAAM,IAAI,QAAQ,CAAC,CAC7B,KAAK,KAAK,CAAC,CACX,YAAY,iCAAiC,CAAC,CAC9C,SAAS,mBAAmB,uBAAuB,CAAC,CACpD,OAAO,aAAa,6BAA6B,IAAI,CAAC,CACtD,OAAO,mBAAmB,6BAA6B,KAAK,CAAC,CAC7D,OACC,mBACA,6DACA,QAAQ,IAAI,CACd,CAAC,CACA,OAAO,qBAAqB,mCAAmC,CAAC,CAChE,OAAO,aAAa,oBAAoB,CAAC,CACzC,OAAO,cAAc,qBAAqB,CAAC,CAC3C,OAAO,cAAc,qBAAqB,CAAC,CAC3C,OAAO,aAAa,oBAAoB,CAAC,CACzC,OAAO,OAAO,YAAsB,SAAS;CAC5C,MAAM,WAAW,uBAAuB,KAAK,GAAG;CAGhD,IAAI,CAAC,UAAU,KAAK,GAAG,GAAG;EACxB,OAAO,KACL,yEAAyE,aAAa,WAAW,8BAA8B,8BAA8B,wDAC/J;EACA,OAAO,MAAM;CACf;CAEA,OAAO,KAAK,aAAa,SAAS,gBAAgB;CAClD,OAAO,KAAK,UAAU,WAAW,OAAO,iBAAiB;CAEzD,MAAM,iBAAiB,MAAM,4BAC3B,KAAK,KACL,sBAAsB,IAAI,CAC5B;CACA,MAAM,QACJ,aAAa,QAAQ,uBAAuB,KAAK,GAAG,IAAI,KAAA;CAC1D,MAAM,EAAE,SAAS,SAAS,wBAAwB;EAChD;EACA;EACA,KAAK,KAAK;EACV,WAAW,KAAK;EAChB,MAAM,KAAK;EACX,GAAI,UAAU,KAAA,IAAY,CAAC,IAAI,EAAE,MAAM;EACvC;CACF,CAAC;CAED,IAAI;EACF,MAAM,SAAS,SAAS,MAAM,KAAK,GAAG;CACxC,SAAS,OAAO;EACd,IAAI,iBAAiB,kBAAkB,MAAM;EAC7C,IAAI,iBAAiB,gBAAgB;GACnC,OAAO,MAAM,4BAA4B,MAAM,MAAM;GACrD,QAAQ,KAAK,MAAM,IAAI;EACzB;EACA,MAAM,UAAU,iBAAiB,QAAQ,MAAM,UAAU,OAAO,KAAK;EACrE,OAAO,MAAM,6BAA6B,SAAS;EACnD,QAAQ,KAAK,CAAC;CAChB;CAEA,OAAO,QAAQ,gCAAgC;AACjD,CAAC"}
1
+ {"version":3,"file":"add.js","names":[],"sources":["../../src/commands/add.ts"],"sourcesContent":["import { Command } from \"commander\";\nimport { logger } from \"../lib/utils/logger\";\nimport { hasConfig } from \"../lib/utils/config\";\nimport {\n detectRegistryPlatform,\n getComponentsJsonStyle,\n resolveRegistryItemUrl,\n} from \"../lib/utils/registry\";\nimport { runSpawn, SpawnExitError, SpawnSignalError } from \"../lib/run-spawn\";\nimport {\n dlxCommand,\n resolvePackageManager,\n type PackageManagerName,\n resolvePackageManagerForCwd,\n} from \"../lib/utils/package-manager\";\n\nexport interface AddComponentsPlan {\n command: string;\n args: string[];\n}\n\nexport function createAddComponentsPlan(params: {\n components: string[];\n packageManager: PackageManagerName;\n yes?: boolean;\n overwrite?: boolean;\n path?: string;\n style?: string;\n platform?: \"web\" | \"native\";\n}): AddComponentsPlan {\n const componentsToAdd = params.components.map((c) => {\n if (!/^[a-zA-Z0-9-/]+$/.test(c)) {\n throw new Error(`Invalid component name: ${c}`);\n }\n return resolveRegistryItemUrl(c, params.style, params.platform);\n });\n\n const [command, dlxArgs] = dlxCommand(params.packageManager);\n const args = [...dlxArgs, \"shadcn@latest\", \"add\", ...componentsToAdd];\n\n // For npm, dlxArgs may already include `--yes` for npx auto-install.\n // This flag is for shadcn's own confirmation prompt.\n if (params.yes) args.push(\"--yes\");\n if (params.overwrite) args.push(\"--overwrite\");\n if (params.path) args.push(\"--path\", params.path);\n\n return { command, args };\n}\n\nexport const add = new Command()\n .name(\"add\")\n .description(\"add a component to your project\")\n .argument(\"<components...>\", \"the components to add\")\n .option(\"-y, --yes\", \"skip confirmation prompt.\", true)\n .option(\"-o, --overwrite\", \"overwrite existing files.\", false)\n .option(\n \"-c, --cwd <cwd>\",\n \"the working directory. defaults to the current directory.\",\n process.cwd(),\n )\n .option(\"-p, --path <path>\", \"the path to add the component to.\")\n .option(\"--use-npm\", \"explicitly use npm\")\n .option(\"--use-pnpm\", \"explicitly use pnpm\")\n .option(\"--use-yarn\", \"explicitly use yarn\")\n .option(\"--use-bun\", \"explicitly use bun\")\n .action(async (components: string[], opts) => {\n const platform = detectRegistryPlatform(opts.cwd);\n\n // Check if project is initialized\n if (!hasConfig(opts.cwd)) {\n logger.warn(\n `It looks like you haven't initialized your project yet. Defaulting to ${platform === \"native\" ? \"the native component tree\" : \"Base UI flavored components\"}. Run 'assistant-ui init' first for a configured setup.`,\n );\n logger.break();\n }\n\n logger.info(`Using the ${platform} registry tree.`);\n logger.step(`Adding ${components.length} component(s)...`);\n\n const packageManager = await resolvePackageManagerForCwd(\n opts.cwd,\n resolvePackageManager(opts),\n );\n const style =\n platform === \"web\" ? getComponentsJsonStyle(opts.cwd) : undefined;\n const { command, args } = createAddComponentsPlan({\n components,\n packageManager,\n yes: opts.yes,\n overwrite: opts.overwrite,\n path: opts.path,\n ...(style === undefined ? {} : { style }),\n platform,\n });\n\n try {\n await runSpawn(command, args, opts.cwd);\n } catch (error) {\n if (error instanceof SpawnSignalError) throw error;\n if (error instanceof SpawnExitError) {\n logger.error(`Process exited with code ${error.code}`);\n process.exit(error.code);\n }\n const message = error instanceof Error ? error.message : String(error);\n logger.error(`Failed to add components: ${message}`);\n process.exit(1);\n }\n\n logger.success(\"Components added successfully!\");\n });\n"],"mappings":";;;;;;;AAqBA,SAAgB,wBAAwB,QAQlB;CACpB,MAAM,kBAAkB,OAAO,WAAW,KAAK,MAAM;EACnD,IAAI,CAAC,mBAAmB,KAAK,CAAC,GAC5B,MAAM,IAAI,MAAM,2BAA2B,GAAG;EAEhD,OAAO,uBAAuB,GAAG,OAAO,OAAO,OAAO,QAAQ;CAChE,CAAC;CAED,MAAM,CAAC,SAAS,WAAW,WAAW,OAAO,cAAc;CAC3D,MAAM,OAAO;EAAC,GAAG;EAAS;EAAiB;EAAO,GAAG;CAAe;CAIpE,IAAI,OAAO,KAAK,KAAK,KAAK,OAAO;CACjC,IAAI,OAAO,WAAW,KAAK,KAAK,aAAa;CAC7C,IAAI,OAAO,MAAM,KAAK,KAAK,UAAU,OAAO,IAAI;CAEhD,OAAO;EAAE;EAAS;CAAK;AACzB;AAEA,MAAa,MAAM,IAAI,QAAQ,CAAC,CAC7B,KAAK,KAAK,CAAC,CACX,YAAY,iCAAiC,CAAC,CAC9C,SAAS,mBAAmB,uBAAuB,CAAC,CACpD,OAAO,aAAa,6BAA6B,IAAI,CAAC,CACtD,OAAO,mBAAmB,6BAA6B,KAAK,CAAC,CAC7D,OACC,mBACA,6DACA,QAAQ,IAAI,CACd,CAAC,CACA,OAAO,qBAAqB,mCAAmC,CAAC,CAChE,OAAO,aAAa,oBAAoB,CAAC,CACzC,OAAO,cAAc,qBAAqB,CAAC,CAC3C,OAAO,cAAc,qBAAqB,CAAC,CAC3C,OAAO,aAAa,oBAAoB,CAAC,CACzC,OAAO,OAAO,YAAsB,SAAS;CAC5C,MAAM,WAAW,uBAAuB,KAAK,GAAG;CAGhD,IAAI,CAAC,UAAU,KAAK,GAAG,GAAG;EACxB,OAAO,KACL,yEAAyE,aAAa,WAAW,8BAA8B,8BAA8B,wDAC/J;EACA,OAAO,MAAM;CACf;CAEA,OAAO,KAAK,aAAa,SAAS,gBAAgB;CAClD,OAAO,KAAK,UAAU,WAAW,OAAO,iBAAiB;CAEzD,MAAM,iBAAiB,MAAM,4BAC3B,KAAK,KACL,sBAAsB,IAAI,CAC5B;CACA,MAAM,QACJ,aAAa,QAAQ,uBAAuB,KAAK,GAAG,IAAI,KAAA;CAC1D,MAAM,EAAE,SAAS,SAAS,wBAAwB;EAChD;EACA;EACA,KAAK,KAAK;EACV,WAAW,KAAK;EAChB,MAAM,KAAK;EACX,GAAI,UAAU,KAAA,IAAY,CAAC,IAAI,EAAE,MAAM;EACvC;CACF,CAAC;CAED,IAAI;EACF,MAAM,SAAS,SAAS,MAAM,KAAK,GAAG;CACxC,SAAS,OAAO;EACd,IAAI,iBAAiB,kBAAkB,MAAM;EAC7C,IAAI,iBAAiB,gBAAgB;GACnC,OAAO,MAAM,4BAA4B,MAAM,MAAM;GACrD,QAAQ,KAAK,MAAM,IAAI;EACzB;EACA,MAAM,UAAU,iBAAiB,QAAQ,MAAM,UAAU,OAAO,KAAK;EACrE,OAAO,MAAM,6BAA6B,SAAS;EACnD,QAAQ,KAAK,CAAC;CAChB;CAEA,OAAO,QAAQ,gCAAgC;AACjD,CAAC"}
@@ -0,0 +1,25 @@
1
+ import { Command } from "commander";
2
+ type SetupOptions = {
3
+ org?: string;
4
+ newOrg?: string;
5
+ project?: string;
6
+ newProject?: string;
7
+ name?: string;
8
+ harnessName?: string;
9
+ backendUrl: string;
10
+ apiUrl: string;
11
+ accessCode?: string;
12
+ setupUrl?: string;
13
+ open?: boolean;
14
+ yes?: boolean;
15
+ skipInstall?: boolean;
16
+ useNpm?: boolean;
17
+ usePnpm?: boolean;
18
+ useYarn?: boolean;
19
+ useBun?: boolean;
20
+ debugSourceRoot?: string;
21
+ };
22
+ export declare const setupCloud: (directory: string, options: SetupOptions) => Promise<void>;
23
+ export declare const cloud: Command;
24
+ export {};
25
+ //# sourceMappingURL=cloud.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"cloud.d.ts","sourceRoot":"","sources":["../../src/commands/cloud.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,OAAO,EAAU,MAAM,WAAW,CAAC;AAuC5C,KAAK,YAAY,GAAG;IAClB,GAAG,CAAC,EAAE,MAAM,CAAC;IACb,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,UAAU,EAAE,MAAM,CAAC;IACnB,MAAM,EAAE,MAAM,CAAC;IACf,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,IAAI,CAAC,EAAE,OAAO,CAAC;IACf,GAAG,CAAC,EAAE,OAAO,CAAC;IACd,WAAW,CAAC,EAAE,OAAO,CAAC;IACtB,MAAM,CAAC,EAAE,OAAO,CAAC;IACjB,OAAO,CAAC,EAAE,OAAO,CAAC;IAClB,OAAO,CAAC,EAAE,OAAO,CAAC;IAClB,MAAM,CAAC,EAAE,OAAO,CAAC;IACjB,eAAe,CAAC,EAAE,MAAM,CAAC;CAC1B,CAAC;AAkLF,eAAO,MAAM,UAAU,GACrB,WAAW,MAAM,EACjB,SAAS,YAAY,KACpB,OAAO,CAAC,IAAI,CAmId,CAAC;AAEF,eAAO,MAAM,KAAK,SAkFf,CAAC"}
@@ -0,0 +1,194 @@
1
+ import { logger } from "../lib/utils/logger.js";
2
+ import { validateCloudUrl } from "../lib/cloud-url.js";
3
+ import { cloudAccessToken, cloudAuthConfig, loginToCloud, logoutFromCloud } from "../lib/cloud-auth.js";
4
+ import { mergeCloudEnvironment, readCloudProjectConfig, readOptionalFile, writeCloudProjectConfig } from "../lib/cloud-config.js";
5
+ import { provisionCloudHarness, resolveProvisionRequest } from "../lib/cloud-provision.js";
6
+ import { create } from "./create.js";
7
+ import { Command, Option } from "commander";
8
+ import path from "node:path";
9
+ import * as p from "@clack/prompts";
10
+ import { createProject, fetchOrganizations, fetchProjects } from "aui-auth/accounts";
11
+ import { access, readFile } from "node:fs/promises";
12
+ import { fileURLToPath } from "node:url";
13
+ //#region src/commands/cloud.ts
14
+ var SetupCancelled = class extends Error {};
15
+ const answer = (value) => {
16
+ if (p.isCancel(value)) throw new SetupCancelled();
17
+ return value;
18
+ };
19
+ const selectResource = async (resources, selected, kind, yes) => {
20
+ if (selected) {
21
+ const resource = resources.find(({ id, slug }) => selected === id || selected === slug);
22
+ if (!resource) throw new Error(`${kind} "${selected}" was not found in your account.`);
23
+ return resource;
24
+ }
25
+ if (resources.length === 0) return null;
26
+ if (resources.length === 1) return resources[0];
27
+ if (yes) throw new Error(`Choose a ${kind.toLowerCase()} with --${kind.toLowerCase()} when using --yes.`);
28
+ const id = answer(await p.select({
29
+ message: `Choose a ${kind.toLowerCase()}`,
30
+ options: resources.map((resource) => ({
31
+ value: resource.id,
32
+ label: `${resource.name} (${resource.slug})`
33
+ }))
34
+ }));
35
+ return resources.find((resource) => resource.id === id);
36
+ };
37
+ const projectSlug = (value) => value.toLowerCase().replace(/[^a-z0-9]+/g, "-").replace(/^-|-$/g, "");
38
+ const organizationForSetup = async (issuer, token, options) => {
39
+ const organizations = await fetchOrganizations({ issuer }, token);
40
+ if (!options.newOrg) {
41
+ const existing = await selectResource(organizations, options.org, "Org", !!options.yes);
42
+ if (existing) return existing;
43
+ }
44
+ const slug = options.newOrg ?? (options.yes ? void 0 : answer(await p.text({
45
+ message: "Choose a slug for your new organization",
46
+ validate: (value) => /^[a-z0-9]+(?:-[a-z0-9]+)*$/.test(value ?? "") ? void 0 : "Use lowercase letters, numbers, and hyphens."
47
+ })));
48
+ if (!slug) throw new Error("No organizations found. Pass --new-org <slug> to create one.");
49
+ const existing = organizations.find((organization) => organization.slug === slug);
50
+ if (existing) return existing;
51
+ const response = await fetch(`${issuer}/api/oidc/organizations`, {
52
+ method: "POST",
53
+ headers: {
54
+ Authorization: `Bearer ${token}`,
55
+ "Content-Type": "application/json"
56
+ },
57
+ body: JSON.stringify({
58
+ name: options.name ?? slug,
59
+ slug
60
+ }),
61
+ signal: AbortSignal.timeout(3e4),
62
+ redirect: "error"
63
+ });
64
+ if (!response.ok) throw new Error(`Could not create organization (${response.status}).`);
65
+ return await response.json();
66
+ };
67
+ const projectForSetup = async (issuer, token, organization, directory, options) => {
68
+ const projects = await fetchProjects({ issuer }, token, { id: organization.id });
69
+ if (!options.newProject) {
70
+ const existing = await selectResource(projects, options.project, "Project", !!options.yes);
71
+ if (existing) return existing;
72
+ }
73
+ const slug = options.newProject ?? projectSlug(path.basename(directory));
74
+ if (!slug) throw new Error("Choose a project slug with --new-project <slug>.");
75
+ const created = await createProject({ issuer }, token, { id: organization.id }, {
76
+ name: options.name ?? path.basename(directory),
77
+ slug
78
+ });
79
+ if ("reason" in created) {
80
+ const existing = projects.find((project) => project.slug === slug);
81
+ if (existing) return existing;
82
+ throw new Error(`Project slug "${slug}" already exists. Select it with --project or choose another slug.`);
83
+ }
84
+ return created;
85
+ };
86
+ const scaffoldCloudProject = async (directory, options) => {
87
+ try {
88
+ await access(path.join(directory, "package.json"));
89
+ if (JSON.parse(await readFile(path.join(directory, ".assistant-ui", "template.json"), "utf8")).template !== "cloud-harness") throw new Error("This directory is not a cloud-harness app. Use a new directory.");
90
+ return;
91
+ } catch (error) {
92
+ if (error.code !== "ENOENT") throw error;
93
+ if (await readOptionalFile(path.join(directory, "package.json"))) throw new Error("This directory already contains an app. Use a new directory for the multiplayer scaffold.");
94
+ }
95
+ const packageRoot = path.resolve(path.dirname(fileURLToPath(import.meta.url)), "../..");
96
+ const args = [
97
+ directory,
98
+ "--template",
99
+ "cloud-harness",
100
+ "--no-skills",
101
+ "--debug-source-root",
102
+ options.debugSourceRoot ?? packageRoot
103
+ ];
104
+ if (options.skipInstall) args.push("--skip-install");
105
+ for (const flag of [
106
+ "useNpm",
107
+ "usePnpm",
108
+ "useYarn",
109
+ "useBun"
110
+ ]) if (options[flag]) args.push(`--use-${flag.slice(3).toLowerCase()}`);
111
+ await create.parseAsync(args, { from: "user" });
112
+ };
113
+ const setupCloud = async (directory, options) => {
114
+ if (options.org && options.newOrg) throw new Error("Choose --org or --new-org.");
115
+ if (options.project && options.newProject) throw new Error("Choose --project or --new-project.");
116
+ validateCloudUrl(options.apiUrl);
117
+ const backend = new URL(options.backendUrl);
118
+ if (backend.username || backend.password || backend.search || backend.hash) throw new Error("Backend URLs must not include credentials, queries, or fragments.");
119
+ if (options.newOrg !== void 0 && !/^[a-z0-9]+(?:-[a-z0-9]+)*$/.test(options.newOrg)) throw new Error("Organization slugs must use lowercase letters, numbers, and hyphens.");
120
+ if (backend.protocol !== "https:" && !(backend.protocol === "http:" && [
121
+ "localhost",
122
+ "127.0.0.1",
123
+ "[::1]"
124
+ ].includes(backend.hostname))) throw new Error("Use an HTTPS backend URL or an HTTP localhost URL for development.");
125
+ const target = path.resolve(directory);
126
+ const previous = await readCloudProjectConfig(target);
127
+ if (previous) {
128
+ if (previous.backendUrl !== backend.href) throw new Error("This harness is configured for another backend URL. Update its backend allowlist in the Cloud dashboard and the backendUrl in .assistant-ui/cloud.json before rerunning setup, or use a new directory.");
129
+ if (options.project && options.project !== previous.projectId && options.project !== previous.projectSlug || options.newProject && options.newProject !== previous.projectSlug || options.org && options.org !== previous.organizationId && options.org !== previous.organizationSlug || options.newOrg && options.newOrg !== previous.organizationSlug) throw new Error("This directory is already configured for another organization or project. Use a new directory.");
130
+ const environment = await readOptionalFile(path.join(target, ".env.local"));
131
+ if (!/^\s*(?:export\s+)?ASSISTANT_API_KEY\s*=\s*.+/m.test(environment)) throw new Error("This project is configured but its .env.local API key is missing. Restore it before running setup again.");
132
+ if (mergeCloudEnvironment(environment, {
133
+ NEXT_PUBLIC_ASSISTANT_BASE_URL: previous.apiOrigin,
134
+ NEXT_PUBLIC_ASSISTANT_HARNESS_URL: previous.harnessOrigin,
135
+ NEXT_PUBLIC_ASSISTANT_WORKSPACE_ID: previous.workspaceId
136
+ }) !== environment) throw new Error("Cloud settings are missing from .env.local. Restore them before running setup again.");
137
+ logger.success(`Already configured: ${previous.projectSlug} / ${previous.harnessId}`);
138
+ return;
139
+ }
140
+ const auth = cloudAuthConfig();
141
+ const token = await cloudAccessToken(auth, {
142
+ noOpen: options.open === false,
143
+ ...options.setupUrl && { setupUrl: options.setupUrl },
144
+ print: logger.info
145
+ });
146
+ const organization = await organizationForSetup(auth.issuer, token, options);
147
+ const project = await projectForSetup(auth.issuer, token, organization, target, options);
148
+ await scaffoldCloudProject(target, options);
149
+ const accessCode = options.accessCode ?? process.env.ASSISTANT_UI_ACCESS_CODE ?? (options.yes ? void 0 : answer(await p.password({ message: "Hackathon access code (leave empty if your plan includes harnesses)" })));
150
+ const request = await resolveProvisionRequest(target, {
151
+ org_id: organization.id,
152
+ project_id: project.id,
153
+ harness_name: options.harnessName ?? `${project.name} chat`,
154
+ backend_urls: backend.protocol === "http:" ? [] : [backend.href],
155
+ allow_localhost: backend.protocol === "http:"
156
+ }, accessCode);
157
+ const result = await provisionCloudHarness(options.apiUrl, token, request);
158
+ await writeCloudProjectConfig(target, {
159
+ organizationId: organization.id,
160
+ organizationSlug: organization.slug,
161
+ projectId: result.project_id,
162
+ projectSlug: project.slug,
163
+ harnessId: result.harness_id,
164
+ harnessOrigin: result.harness_origin,
165
+ apiOrigin: result.api_origin,
166
+ workspaceId: result.workspace_id,
167
+ backendUrl: backend.href
168
+ }, result.api_key);
169
+ logger.success(`Multiplayer chat configured for ${project.name}.`);
170
+ logger.info(`Project: ${target}`);
171
+ logger.info("Add OPENAI_API_KEY to .env.local, then start the app with your package manager's dev command.");
172
+ logger.info(backend.protocol === "http:" ? `Open ${backend.origin}/#main in two browser windows to try shared chat. Deploy or expose the app to share it with teammates.` : "Open your deployed app and use \"Share this chat\" to invite teammates to the same conversation.");
173
+ };
174
+ const cloud = new Command().name("cloud").description("sign in and set up a multiplayer Assistant Cloud chat").addCommand(new Command("login").description("sign in to Assistant Cloud using your browser").option("--no-open", "print the device sign-in URL without opening a browser").option("--setup-url <url>", "show device sign-in in an active setup wizard").action(async (options) => {
175
+ await loginToCloud(cloudAuthConfig(), {
176
+ noOpen: options.open === false,
177
+ ...options.setupUrl && { setupUrl: options.setupUrl },
178
+ print: logger.info
179
+ });
180
+ })).addCommand(new Command("logout").description("revoke your CLI login and remove saved credentials").action(async () => {
181
+ await logoutFromCloud(cloudAuthConfig());
182
+ logger.success("Signed out.");
183
+ })).addCommand(new Command("setup").description("create a shared AI chat and provision its cloud harness").argument("[directory]", "new project directory", "multiplayer-chat").option("--org <id-or-slug>", "use an existing organization").option("--new-org <slug>", "create an organization").option("--project <id-or-slug>", "use an existing project").option("--new-project <slug>", "create a project").option("--name <name>", "display name for a new project or organization").option("--harness-name <name>", "name for the multiplayer harness").option("--backend-url <url>", "absolute URL of the app's chat route", "http://localhost:3000/api/chat").option("--api-url <url>", "Assistant Cloud management URL", process.env.ASSISTANT_UI_CLOUD_URL ?? "https://cloud.assistant-ui.com").option("--access-code <code>", "redeem your hackathon harness access code").option("--no-open", "print the device sign-in URL without opening a browser").option("--setup-url <url>", "show device sign-in in an active setup wizard").option("--yes", "skip prompts; select resources with flags").option("--skip-install", "skip installing scaffold dependencies").option("--use-npm", "install with npm").option("--use-pnpm", "install with pnpm").option("--use-yarn", "install with yarn").option("--use-bun", "install with bun").addOption(new Option("--debug-source-root <path>", "local assistant-ui source root").hideHelp()).action(async (directory, options) => {
184
+ try {
185
+ await setupCloud(directory, options);
186
+ } catch (error) {
187
+ if (!(error instanceof SetupCancelled)) throw error;
188
+ p.cancel("Cloud setup cancelled. Rerun the same command to resume.");
189
+ }
190
+ }));
191
+ //#endregion
192
+ export { cloud, setupCloud };
193
+
194
+ //# sourceMappingURL=cloud.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"cloud.js","names":[],"sources":["../../src/commands/cloud.ts"],"sourcesContent":["import { Command, Option } from \"commander\";\nimport * as p from \"@clack/prompts\";\nimport {\n createProject,\n fetchOrganizations,\n fetchProjects,\n type AccountsOrganization,\n type AccountsProject,\n} from \"aui-auth/accounts\";\nimport { access, readFile } from \"node:fs/promises\";\nimport path from \"node:path\";\nimport { fileURLToPath } from \"node:url\";\nimport {\n cloudAccessToken,\n cloudAuthConfig,\n loginToCloud,\n logoutFromCloud,\n validateCloudUrl,\n} from \"../lib/cloud-auth\";\nimport {\n readCloudProjectConfig,\n mergeCloudEnvironment,\n readOptionalFile,\n writeCloudProjectConfig,\n} from \"../lib/cloud-config\";\nimport {\n provisionCloudHarness,\n resolveProvisionRequest,\n} from \"../lib/cloud-provision\";\nimport { logger } from \"../lib/utils/logger\";\nimport { create } from \"./create\";\n\nclass SetupCancelled extends Error {}\n\nconst answer = <T>(value: T | symbol): Exclude<T, symbol> => {\n if (p.isCancel(value)) throw new SetupCancelled();\n return value as Exclude<T, symbol>;\n};\n\ntype SetupOptions = {\n org?: string;\n newOrg?: string;\n project?: string;\n newProject?: string;\n name?: string;\n harnessName?: string;\n backendUrl: string;\n apiUrl: string;\n accessCode?: string;\n setupUrl?: string;\n open?: boolean;\n yes?: boolean;\n skipInstall?: boolean;\n useNpm?: boolean;\n usePnpm?: boolean;\n useYarn?: boolean;\n useBun?: boolean;\n debugSourceRoot?: string;\n};\n\nconst selectResource = async <\n T extends { id: string; slug: string; name: string },\n>(\n resources: T[],\n selected: string | undefined,\n kind: string,\n yes: boolean,\n): Promise<T | null> => {\n if (selected) {\n const resource = resources.find(\n ({ id, slug }) => selected === id || selected === slug,\n );\n if (!resource)\n throw new Error(`${kind} \"${selected}\" was not found in your account.`);\n return resource;\n }\n if (resources.length === 0) return null;\n if (resources.length === 1) return resources[0]!;\n if (yes)\n throw new Error(\n `Choose a ${kind.toLowerCase()} with --${kind.toLowerCase()} when using --yes.`,\n );\n const id = answer(\n await p.select({\n message: `Choose a ${kind.toLowerCase()}`,\n options: resources.map((resource) => ({\n value: resource.id,\n label: `${resource.name} (${resource.slug})`,\n })),\n }),\n );\n return resources.find((resource) => resource.id === id)!;\n};\n\nconst projectSlug = (value: string): string =>\n value\n .toLowerCase()\n .replace(/[^a-z0-9]+/g, \"-\")\n .replace(/^-|-$/g, \"\");\n\nconst organizationForSetup = async (\n issuer: string,\n token: string,\n options: SetupOptions,\n): Promise<AccountsOrganization> => {\n const organizations = await fetchOrganizations({ issuer }, token);\n if (!options.newOrg) {\n const existing = await selectResource(\n organizations,\n options.org,\n \"Org\",\n !!options.yes,\n );\n if (existing) return existing;\n }\n const slug =\n options.newOrg ??\n (options.yes\n ? undefined\n : answer(\n await p.text({\n message: \"Choose a slug for your new organization\",\n validate: (value) =>\n /^[a-z0-9]+(?:-[a-z0-9]+)*$/.test(value ?? \"\")\n ? undefined\n : \"Use lowercase letters, numbers, and hyphens.\",\n }),\n ));\n if (!slug)\n throw new Error(\n \"No organizations found. Pass --new-org <slug> to create one.\",\n );\n const existing = organizations.find(\n (organization) => organization.slug === slug,\n );\n if (existing) return existing;\n const response = await fetch(`${issuer}/api/oidc/organizations`, {\n method: \"POST\",\n headers: {\n Authorization: `Bearer ${token}`,\n \"Content-Type\": \"application/json\",\n },\n body: JSON.stringify({ name: options.name ?? slug, slug }),\n signal: AbortSignal.timeout(30_000),\n redirect: \"error\",\n });\n if (!response.ok)\n throw new Error(`Could not create organization (${response.status}).`);\n return (await response.json()) as AccountsOrganization;\n};\n\nconst projectForSetup = async (\n issuer: string,\n token: string,\n organization: AccountsOrganization,\n directory: string,\n options: SetupOptions,\n): Promise<AccountsProject> => {\n const projects = await fetchProjects({ issuer }, token, {\n id: organization.id,\n });\n if (!options.newProject) {\n const existing = await selectResource(\n projects,\n options.project,\n \"Project\",\n !!options.yes,\n );\n if (existing) return existing;\n }\n const slug = options.newProject ?? projectSlug(path.basename(directory));\n if (!slug)\n throw new Error(\"Choose a project slug with --new-project <slug>.\");\n const created = await createProject(\n { issuer },\n token,\n { id: organization.id },\n {\n name: options.name ?? path.basename(directory),\n slug,\n },\n );\n if (\"reason\" in created) {\n const existing = projects.find((project) => project.slug === slug);\n if (existing) return existing;\n throw new Error(\n `Project slug \"${slug}\" already exists. Select it with --project or choose another slug.`,\n );\n }\n return created;\n};\n\nconst scaffoldCloudProject = async (\n directory: string,\n options: SetupOptions,\n): Promise<void> => {\n try {\n await access(path.join(directory, \"package.json\"));\n const marker = JSON.parse(\n await readFile(\n path.join(directory, \".assistant-ui\", \"template.json\"),\n \"utf8\",\n ),\n ) as { template?: string };\n if (marker.template !== \"cloud-harness\")\n throw new Error(\n \"This directory is not a cloud-harness app. Use a new directory.\",\n );\n return;\n } catch (error) {\n if ((error as NodeJS.ErrnoException).code !== \"ENOENT\") throw error;\n if (await readOptionalFile(path.join(directory, \"package.json\"))) {\n throw new Error(\n \"This directory already contains an app. Use a new directory for the multiplayer scaffold.\",\n );\n }\n }\n const packageRoot = path.resolve(\n path.dirname(fileURLToPath(import.meta.url)),\n \"../..\",\n );\n const args = [\n directory,\n \"--template\",\n \"cloud-harness\",\n \"--no-skills\",\n \"--debug-source-root\",\n options.debugSourceRoot ?? packageRoot,\n ];\n if (options.skipInstall) args.push(\"--skip-install\");\n for (const flag of [\"useNpm\", \"usePnpm\", \"useYarn\", \"useBun\"] as const) {\n if (options[flag]) args.push(`--use-${flag.slice(3).toLowerCase()}`);\n }\n await create.parseAsync(args, { from: \"user\" });\n};\n\nexport const setupCloud = async (\n directory: string,\n options: SetupOptions,\n): Promise<void> => {\n if (options.org && options.newOrg)\n throw new Error(\"Choose --org or --new-org.\");\n if (options.project && options.newProject)\n throw new Error(\"Choose --project or --new-project.\");\n validateCloudUrl(options.apiUrl);\n const backend = new URL(options.backendUrl);\n if (backend.username || backend.password || backend.search || backend.hash)\n throw new Error(\n \"Backend URLs must not include credentials, queries, or fragments.\",\n );\n if (\n options.newOrg !== undefined &&\n !/^[a-z0-9]+(?:-[a-z0-9]+)*$/.test(options.newOrg)\n )\n throw new Error(\n \"Organization slugs must use lowercase letters, numbers, and hyphens.\",\n );\n if (\n backend.protocol !== \"https:\" &&\n !(\n backend.protocol === \"http:\" &&\n [\"localhost\", \"127.0.0.1\", \"[::1]\"].includes(backend.hostname)\n )\n ) {\n throw new Error(\n \"Use an HTTPS backend URL or an HTTP localhost URL for development.\",\n );\n }\n const target = path.resolve(directory);\n const previous = await readCloudProjectConfig(target);\n if (previous) {\n if (previous.backendUrl !== backend.href)\n throw new Error(\n \"This harness is configured for another backend URL. Update its backend allowlist in the Cloud dashboard and the backendUrl in .assistant-ui/cloud.json before rerunning setup, or use a new directory.\",\n );\n if (\n (options.project &&\n options.project !== previous.projectId &&\n options.project !== previous.projectSlug) ||\n (options.newProject && options.newProject !== previous.projectSlug) ||\n (options.org &&\n options.org !== previous.organizationId &&\n options.org !== previous.organizationSlug) ||\n (options.newOrg && options.newOrg !== previous.organizationSlug)\n )\n throw new Error(\n \"This directory is already configured for another organization or project. Use a new directory.\",\n );\n const environment = await readOptionalFile(path.join(target, \".env.local\"));\n if (!/^\\s*(?:export\\s+)?ASSISTANT_API_KEY\\s*=\\s*.+/m.test(environment))\n throw new Error(\n \"This project is configured but its .env.local API key is missing. Restore it before running setup again.\",\n );\n const expected = mergeCloudEnvironment(environment, {\n NEXT_PUBLIC_ASSISTANT_BASE_URL: previous.apiOrigin,\n NEXT_PUBLIC_ASSISTANT_HARNESS_URL: previous.harnessOrigin,\n NEXT_PUBLIC_ASSISTANT_WORKSPACE_ID: previous.workspaceId,\n });\n if (expected !== environment)\n throw new Error(\n \"Cloud settings are missing from .env.local. Restore them before running setup again.\",\n );\n logger.success(\n `Already configured: ${previous.projectSlug} / ${previous.harnessId}`,\n );\n return;\n }\n const auth = cloudAuthConfig();\n const token = await cloudAccessToken(auth, {\n noOpen: options.open === false,\n ...(options.setupUrl && { setupUrl: options.setupUrl }),\n print: logger.info,\n });\n const organization = await organizationForSetup(auth.issuer, token, options);\n const project = await projectForSetup(\n auth.issuer,\n token,\n organization,\n target,\n options,\n );\n await scaffoldCloudProject(target, options);\n const accessCode =\n options.accessCode ??\n process.env.ASSISTANT_UI_ACCESS_CODE ??\n (options.yes\n ? undefined\n : answer(\n await p.password({\n message:\n \"Hackathon access code (leave empty if your plan includes harnesses)\",\n }),\n ));\n const request = await resolveProvisionRequest(\n target,\n {\n org_id: organization.id,\n project_id: project.id,\n harness_name: options.harnessName ?? `${project.name} chat`,\n backend_urls: backend.protocol === \"http:\" ? [] : [backend.href],\n allow_localhost: backend.protocol === \"http:\",\n },\n accessCode,\n );\n const result = await provisionCloudHarness(options.apiUrl, token, request);\n await writeCloudProjectConfig(\n target,\n {\n organizationId: organization.id,\n organizationSlug: organization.slug,\n projectId: result.project_id,\n projectSlug: project.slug,\n harnessId: result.harness_id,\n harnessOrigin: result.harness_origin,\n apiOrigin: result.api_origin,\n workspaceId: result.workspace_id,\n backendUrl: backend.href,\n },\n result.api_key,\n );\n logger.success(`Multiplayer chat configured for ${project.name}.`);\n logger.info(`Project: ${target}`);\n logger.info(\n \"Add OPENAI_API_KEY to .env.local, then start the app with your package manager's dev command.\",\n );\n logger.info(\n backend.protocol === \"http:\"\n ? `Open ${backend.origin}/#main in two browser windows to try shared chat. Deploy or expose the app to share it with teammates.`\n : 'Open your deployed app and use \"Share this chat\" to invite teammates to the same conversation.',\n );\n};\n\nexport const cloud = new Command()\n .name(\"cloud\")\n .description(\"sign in and set up a multiplayer Assistant Cloud chat\")\n .addCommand(\n new Command(\"login\")\n .description(\"sign in to Assistant Cloud using your browser\")\n .option(\n \"--no-open\",\n \"print the device sign-in URL without opening a browser\",\n )\n .option(\n \"--setup-url <url>\",\n \"show device sign-in in an active setup wizard\",\n )\n .action(async (options: { open?: boolean; setupUrl?: string }) => {\n await loginToCloud(cloudAuthConfig(), {\n noOpen: options.open === false,\n ...(options.setupUrl && { setupUrl: options.setupUrl }),\n print: logger.info,\n });\n }),\n )\n .addCommand(\n new Command(\"logout\")\n .description(\"revoke your CLI login and remove saved credentials\")\n .action(async () => {\n await logoutFromCloud(cloudAuthConfig());\n logger.success(\"Signed out.\");\n }),\n )\n .addCommand(\n new Command(\"setup\")\n .description(\"create a shared AI chat and provision its cloud harness\")\n .argument(\"[directory]\", \"new project directory\", \"multiplayer-chat\")\n .option(\"--org <id-or-slug>\", \"use an existing organization\")\n .option(\"--new-org <slug>\", \"create an organization\")\n .option(\"--project <id-or-slug>\", \"use an existing project\")\n .option(\"--new-project <slug>\", \"create a project\")\n .option(\"--name <name>\", \"display name for a new project or organization\")\n .option(\"--harness-name <name>\", \"name for the multiplayer harness\")\n .option(\n \"--backend-url <url>\",\n \"absolute URL of the app's chat route\",\n \"http://localhost:3000/api/chat\",\n )\n .option(\n \"--api-url <url>\",\n \"Assistant Cloud management URL\",\n process.env.ASSISTANT_UI_CLOUD_URL ?? \"https://cloud.assistant-ui.com\",\n )\n .option(\n \"--access-code <code>\",\n \"redeem your hackathon harness access code\",\n )\n .option(\n \"--no-open\",\n \"print the device sign-in URL without opening a browser\",\n )\n .option(\n \"--setup-url <url>\",\n \"show device sign-in in an active setup wizard\",\n )\n .option(\"--yes\", \"skip prompts; select resources with flags\")\n .option(\"--skip-install\", \"skip installing scaffold dependencies\")\n .option(\"--use-npm\", \"install with npm\")\n .option(\"--use-pnpm\", \"install with pnpm\")\n .option(\"--use-yarn\", \"install with yarn\")\n .option(\"--use-bun\", \"install with bun\")\n .addOption(\n new Option(\n \"--debug-source-root <path>\",\n \"local assistant-ui source root\",\n ).hideHelp(),\n )\n .action(async (directory: string, options: SetupOptions) => {\n try {\n await setupCloud(directory, options);\n } catch (error) {\n if (!(error instanceof SetupCancelled)) throw error;\n p.cancel(\"Cloud setup cancelled. Rerun the same command to resume.\");\n }\n }),\n );\n"],"mappings":"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"}
@@ -1 +1 @@
1
- {"version":3,"file":"create.d.ts","sourceRoot":"","sources":["../../src/commands/create.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,OAAO,EAAU,MAAM,WAAW,CAAC;AAI5C,OAAO,KAAK,CAAC,MAAM,gBAAgB,CAAC;AAwBpC,MAAM,WAAW,eAAe;IAC9B,IAAI,EAAE,MAAM,CAAC;IACb,KAAK,EAAE,MAAM,CAAC;IACd,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,QAAQ,EAAE,UAAU,GAAG,SAAS,CAAC;IACjC,IAAI,EAAE,MAAM,CAAC;IACb,kBAAkB,EAAE,OAAO,CAAC;CAC7B;AAED,eAAO,MAAM,gBAAgB,EAAE,eAAe,EAmP7C,CAAC;AAiBF,wBAAsB,cAAc,CAAC,MAAM,EAAE;IAC3C,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,UAAU,CAAC,EAAE,OAAO,CAAC;IACrB,MAAM,CAAC,EAAE,OAAO,CAAC,CAAC,MAAM,CAAC;IACzB,QAAQ,CAAC,EAAE,OAAO,CAAC,CAAC,QAAQ,CAAC;CAC9B,GAAG,OAAO,CAAC,eAAe,GAAG,IAAI,CAAC,CAyElC;AAED,wBAAgB,6BAA6B,CAAC,MAAM,EAAE;IACpD,gBAAgB,CAAC,EAAE,MAAM,CAAC;IAC1B,UAAU,CAAC,EAAE,OAAO,CAAC;CACtB,GAAG,MAAM,GAAG,SAAS,CAMrB;AAED,eAAO,MAAM,yBAAyB,eAAe,CAAC;AAEtD,eAAO,MAAM,wBAAwB;;;;uBAIhB,MAAM;CAY1B,CAAC;AAEF,wBAAgB,+BAA+B,CAAC,MAAM,EAAE;IACtD,kBAAkB,EAAE,MAAM,CAAC;IAC3B,GAAG,CAAC,EAAE,MAAM,CAAC;IACb,QAAQ,CAAC,EAAE,MAAM,CAAC,QAAQ,CAAC;CAC5B,GAAG;IAAE,OAAO,EAAE,MAAM,CAAC;IAAC,SAAS,EAAE,MAAM,CAAA;CAAE,CA8BzC;AAKD,wBAAgB,gBAAgB,CAAC,MAAM,EAAE,MAAM,GAAG,MAAM,CAKvD;AAED,MAAM,WAAW,uBAAuB;IACtC,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,MAAM,CAAC,EAAE,OAAO,CAAC;IACjB,GAAG,CAAC,EAAE,OAAO,CAAC;CACf;AAED,MAAM,WAAW,wBAAwB;IACvC,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,MAAM,CAAC,EAAE,MAAM,CAAC;CACjB;AAYD,wBAAgB,uBAAuB,CACrC,IAAI,EAAE,uBAAuB,GAC5B,wBAAwB,CAkC1B;AAED,eAAO,MAAM,MAAM,SA+Uf,CAAC"}
1
+ {"version":3,"file":"create.d.ts","sourceRoot":"","sources":["../../src/commands/create.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,OAAO,EAAU,MAAM,WAAW,CAAC;AAI5C,OAAO,KAAK,CAAC,MAAM,gBAAgB,CAAC;AA0BpC,MAAM,WAAW,eAAe;IAC9B,IAAI,EAAE,MAAM,CAAC;IACb,KAAK,EAAE,MAAM,CAAC;IACd,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,QAAQ,EAAE,UAAU,GAAG,SAAS,CAAC;IACjC,IAAI,EAAE,MAAM,CAAC;IACb,kBAAkB,EAAE,OAAO,CAAC;CAC7B;AAED,eAAO,MAAM,gBAAgB,EAAE,eAAe,EA2P7C,CAAC;AAiBF,wBAAsB,cAAc,CAAC,MAAM,EAAE;IAC3C,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,UAAU,CAAC,EAAE,OAAO,CAAC;IACrB,MAAM,CAAC,EAAE,OAAO,CAAC,CAAC,MAAM,CAAC;IACzB,QAAQ,CAAC,EAAE,OAAO,CAAC,CAAC,QAAQ,CAAC;CAC9B,GAAG,OAAO,CAAC,eAAe,GAAG,IAAI,CAAC,CAyElC;AAED,wBAAgB,6BAA6B,CAAC,MAAM,EAAE;IACpD,gBAAgB,CAAC,EAAE,MAAM,CAAC;IAC1B,UAAU,CAAC,EAAE,OAAO,CAAC;CACtB,GAAG,MAAM,GAAG,SAAS,CAMrB;AAED,eAAO,MAAM,yBAAyB,eAAe,CAAC;AAEtD,eAAO,MAAM,wBAAwB;;;;uBAIhB,MAAM;CAY1B,CAAC;AAEF,wBAAgB,+BAA+B,CAAC,MAAM,EAAE;IACtD,kBAAkB,EAAE,MAAM,CAAC;IAC3B,GAAG,CAAC,EAAE,MAAM,CAAC;IACb,QAAQ,CAAC,EAAE,MAAM,CAAC,QAAQ,CAAC;CAC5B,GAAG;IAAE,OAAO,EAAE,MAAM,CAAC;IAAC,SAAS,EAAE,MAAM,CAAA;CAAE,CA8BzC;AAKD,wBAAgB,gBAAgB,CAAC,MAAM,EAAE,MAAM,GAAG,MAAM,CAKvD;AAED,MAAM,WAAW,uBAAuB;IACtC,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,MAAM,CAAC,EAAE,OAAO,CAAC;IACjB,GAAG,CAAC,EAAE,OAAO,CAAC;CACf;AAED,MAAM,WAAW,wBAAwB;IACvC,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,MAAM,CAAC,EAAE,MAAM,CAAC;CACjB;AAYD,wBAAgB,uBAAuB,CACrC,IAAI,EAAE,uBAAuB,GAC5B,wBAAwB,CAkC1B;AAED,eAAO,MAAM,MAAM,SA+Uf,CAAC"}
@@ -1,8 +1,8 @@
1
1
  import { logger } from "../lib/utils/logger.js";
2
2
  import { SpawnExitError, SpawnSignalError, hasActiveSpawn, runSpawn } from "../lib/run-spawn.js";
3
- import { resolvePackageManagerForCwd } from "../lib/utils/package-manager.js";
4
- import { cleanupPendingProjectDownloads, dlxCommand, downloadProject, resolveLatestReleaseRef, resolvePackageManager, scaffoldProject, transformProject } from "../lib/create-project.js";
3
+ import { dlxCommand, resolvePackageManager, resolvePackageManagerForCwd } from "../lib/utils/package-manager.js";
5
4
  import { buildSkillsAddCommand, resolveSkillsInstall } from "../lib/agent-skill.js";
5
+ import { cleanupPendingProjectDownloads, downloadProject, resolveLatestReleaseRef, scaffoldProject, transformProject } from "../lib/create-project.js";
6
6
  import { Command, Option } from "commander";
7
7
  import chalk from "chalk";
8
8
  import fs from "node:fs";
@@ -42,6 +42,14 @@ const PROJECT_METADATA = [
42
42
  path: "templates/cloud-clerk",
43
43
  hasLocalComponents: false
44
44
  },
45
+ {
46
+ name: "cloud-harness",
47
+ label: "Shared cloud chat",
48
+ description: "A hosted harness with a shared conversation across browsers",
49
+ category: "template",
50
+ path: "templates/cloud-harness",
51
+ hasLocalComponents: true
52
+ },
45
53
  {
46
54
  name: "langchain",
47
55
  label: "LangChain",