assistant-ui 0.0.124 → 0.0.126

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 (32) hide show
  1. package/README.md +7 -0
  2. package/dist/codemods/v0-12/primitive-if-to-aui-if.d.ts.map +1 -1
  3. package/dist/codemods/v0-12/primitive-if-to-aui-if.js +4 -4
  4. package/dist/codemods/v0-12/primitive-if-to-aui-if.js.map +1 -1
  5. package/dist/commands/cloud.d.ts.map +1 -1
  6. package/dist/commands/cloud.js +12 -3
  7. package/dist/commands/cloud.js.map +1 -1
  8. package/dist/commands/info.d.ts.map +1 -1
  9. package/dist/commands/info.js +8 -1
  10. package/dist/commands/info.js.map +1 -1
  11. package/dist/index.js +0 -0
  12. package/dist/lib/cloud-auth.d.ts +1 -0
  13. package/dist/lib/cloud-auth.d.ts.map +1 -1
  14. package/dist/lib/cloud-auth.js +4 -3
  15. package/dist/lib/cloud-auth.js.map +1 -1
  16. package/dist/lib/cloud-remote.d.ts +22 -0
  17. package/dist/lib/cloud-remote.d.ts.map +1 -0
  18. package/dist/lib/cloud-remote.js +74 -0
  19. package/dist/lib/cloud-remote.js.map +1 -0
  20. package/package.json +7 -7
  21. package/src/codemods/v0-12/__tests__/primitive-if-to-aui-if.test.ts +35 -1
  22. package/src/codemods/v0-12/primitive-if-to-aui-if.ts +5 -4
  23. package/src/commands/cloud.test.ts +58 -0
  24. package/src/commands/cloud.ts +19 -2
  25. package/src/commands/info.ts +26 -1
  26. package/src/lib/cloud-auth.ts +14 -8
  27. package/src/lib/cloud-remote.test.ts +156 -0
  28. package/src/lib/cloud-remote.ts +150 -0
  29. package/templates/cloud-harness/components/assistant-ui/elements/attachment-state.ts +59 -0
  30. package/templates/cloud-harness/components/assistant-ui/elements/attachment.aui.tsx +11 -44
  31. package/templates/cloud-harness/package.json +11 -11
  32. package/templates/cloud-harness/.gitignore +0 -42
@@ -0,0 +1,150 @@
1
+ import { validateCloudUrl } from "./cloud-url";
2
+
3
+ export const CLOUD_CLI_RUN_PATH = "/api/cli/run";
4
+
5
+ export type CloudCliAction = { type: string; [key: string]: unknown };
6
+
7
+ export type CloudCliResponse = {
8
+ stdout?: string;
9
+ stderr?: string;
10
+ exitCode: number;
11
+ actions?: CloudCliAction[];
12
+ };
13
+
14
+ const SAFE = /^[A-Za-z0-9_@%+=:,./-]+$/;
15
+
16
+ export const joinCloudArgs = (args: readonly string[]): string =>
17
+ args
18
+ .map((arg) => (SAFE.test(arg) ? arg : `'${arg.replaceAll("'", `'\\''`)}'`))
19
+ .join(" ");
20
+
21
+ export const parseCloudCliResponse = (
22
+ value: unknown,
23
+ ): CloudCliResponse | null => {
24
+ if (!value || typeof value !== "object") return null;
25
+ const body = value as Record<string, unknown>;
26
+ const exitCode = body["exitCode"];
27
+ if (
28
+ typeof exitCode !== "number" ||
29
+ !Number.isInteger(exitCode) ||
30
+ exitCode < 0 ||
31
+ exitCode > 255
32
+ ) {
33
+ return null;
34
+ }
35
+ for (const key of ["stdout", "stderr"]) {
36
+ if (body[key] !== undefined && typeof body[key] !== "string") return null;
37
+ }
38
+ const actions = body["actions"];
39
+ if (
40
+ actions !== undefined &&
41
+ !(
42
+ Array.isArray(actions) &&
43
+ actions.every(
44
+ (action) =>
45
+ !!action &&
46
+ typeof action === "object" &&
47
+ typeof (action as CloudCliAction).type === "string",
48
+ )
49
+ )
50
+ ) {
51
+ return null;
52
+ }
53
+ return body as CloudCliResponse;
54
+ };
55
+
56
+ const cliVersion: string =
57
+ typeof __AUI_PACKAGE_VERSION__ === "string"
58
+ ? __AUI_PACKAGE_VERSION__
59
+ : "0.0.0";
60
+
61
+ export const sendCloudCommand = async (
62
+ cloudUrl: string,
63
+ args: readonly string[],
64
+ accessToken: string | null,
65
+ ): Promise<CloudCliResponse> => {
66
+ const url = `${validateCloudUrl(cloudUrl)}${CLOUD_CLI_RUN_PATH}`;
67
+ let response: Response;
68
+ try {
69
+ response = await fetch(url, {
70
+ method: "POST",
71
+ headers: {
72
+ "Content-Type": "application/json",
73
+ ...(accessToken ? { Authorization: `Bearer ${accessToken}` } : {}),
74
+ },
75
+ body: JSON.stringify({
76
+ command: joinCloudArgs(args),
77
+ client: {
78
+ name: "assistant-ui",
79
+ version: cliVersion,
80
+ platform: `${process.platform}-${process.arch}`,
81
+ },
82
+ }),
83
+ redirect: "error",
84
+ signal: AbortSignal.timeout(60_000),
85
+ });
86
+ } catch (error) {
87
+ const cause = (error as Error).cause as NodeJS.ErrnoException | undefined;
88
+ throw new Error(
89
+ `Could not reach ${url}: ${cause?.message || cause?.code || (error as Error).message}`,
90
+ );
91
+ }
92
+ const body = parseCloudCliResponse(await response.json().catch(() => null));
93
+ if (!body) {
94
+ throw new Error(
95
+ `Unexpected response from ${url} (${response.status} ${response.statusText}).`,
96
+ );
97
+ }
98
+ return body;
99
+ };
100
+
101
+ // A response naming an action this client lacks fails before printing, so the
102
+ // server can roll a new action out behind the client version it is sent.
103
+ const ACTION_HANDLERS: Record<
104
+ string,
105
+ (action: CloudCliAction) => Promise<number>
106
+ > = {};
107
+
108
+ export const runCloudCommand = async (
109
+ args: readonly string[],
110
+ deps: {
111
+ cloudUrl: string;
112
+ accessToken: () => Promise<string | null>;
113
+ stdout: (text: string) => void;
114
+ stderr: (text: string) => void;
115
+ send?: typeof sendCloudCommand;
116
+ },
117
+ ): Promise<number> => {
118
+ let response: CloudCliResponse;
119
+ try {
120
+ response = await (deps.send ?? sendCloudCommand)(
121
+ deps.cloudUrl,
122
+ args,
123
+ await deps.accessToken().catch((error: unknown) => {
124
+ deps.stderr(
125
+ `${error instanceof Error ? error.message : String(error)}\n`,
126
+ );
127
+ return null;
128
+ }),
129
+ );
130
+ } catch (error) {
131
+ deps.stderr(`${error instanceof Error ? error.message : String(error)}\n`);
132
+ return 1;
133
+ }
134
+ const unknown = response.actions?.find(
135
+ (action) => !Object.hasOwn(ACTION_HANDLERS, action.type),
136
+ );
137
+ if (unknown) {
138
+ deps.stderr(
139
+ `This command needs a newer assistant-ui (unsupported action "${unknown.type}"). Update the CLI and try again.\n`,
140
+ );
141
+ return 1;
142
+ }
143
+ if (response.stdout) deps.stdout(response.stdout);
144
+ if (response.stderr) deps.stderr(response.stderr);
145
+ for (const action of response.actions ?? []) {
146
+ const code = await ACTION_HANDLERS[action.type]!(action);
147
+ if (code !== 0) return code;
148
+ }
149
+ return response.exitCode;
150
+ };
@@ -0,0 +1,59 @@
1
+ "use client";
2
+
3
+ import { useAui, useAuiState } from "@assistant-ui/react";
4
+ import { useAttachmentSrc } from "@/hooks/use-attachment-src";
5
+
6
+ export function useAttachmentState() {
7
+ const aui = useAui();
8
+ const isComposer = aui.attachment.source !== "message";
9
+ const src = useAttachmentSrc();
10
+
11
+ const isImage = useAuiState((s) => s.attachment.type === "image");
12
+ const name = useAuiState((s) => s.attachment.name);
13
+ const typeLabel = useAuiState((s) => {
14
+ const type = s.attachment.type;
15
+ switch (type) {
16
+ case "image":
17
+ return "Image";
18
+ case "document":
19
+ return "Document";
20
+ case "file":
21
+ return "File";
22
+ default:
23
+ return type;
24
+ }
25
+ });
26
+
27
+ // An attachment on a submission is still being prepared, whether or not the
28
+ // adapter reports progress while it uploads.
29
+ const uploadState = useAuiState((s) =>
30
+ s.attachment.status.type === "incomplete" &&
31
+ s.attachment.status.reason === "error"
32
+ ? "error"
33
+ : s.attachment.status.type === "running" ||
34
+ (s.optional.message?.submission !== undefined &&
35
+ s.attachment.status.type !== "complete")
36
+ ? "uploading"
37
+ : undefined,
38
+ );
39
+ const isUploading = uploadState === "uploading";
40
+ const isError = uploadState === "error";
41
+
42
+ const errorMessage = useAuiState((s) =>
43
+ s.attachment.status.type === "incomplete" &&
44
+ s.attachment.status.reason === "error"
45
+ ? (s.attachment.status.message ?? "Upload failed")
46
+ : undefined,
47
+ );
48
+
49
+ return {
50
+ isComposer,
51
+ src,
52
+ isImage,
53
+ name,
54
+ typeLabel,
55
+ isUploading,
56
+ isError,
57
+ errorMessage,
58
+ };
59
+ }
@@ -17,8 +17,6 @@ import {
17
17
  AttachmentPrimitive,
18
18
  ComposerPrimitive,
19
19
  MessagePrimitive,
20
- useAuiState,
21
- useAui,
22
20
  } from "@assistant-ui/react";
23
21
  import {
24
22
  Tooltip,
@@ -34,7 +32,7 @@ import {
34
32
  } from "@/components/ui/dialog";
35
33
  import { Avatar, AvatarImage, AvatarFallback } from "@/components/ui/avatar";
36
34
  import { TooltipIconButton } from "@/components/assistant-ui/elements/tooltip-icon-button";
37
- import { useAttachmentSrc } from "@/hooks/use-attachment-src";
35
+ import { useAttachmentState } from "./attachment-state";
38
36
  import { cn } from "@/lib/utils";
39
37
 
40
38
  type AttachmentPreviewProps = {
@@ -112,47 +110,16 @@ const AttachmentThumb: FC<{ src: string | undefined }> = ({ src }) => {
112
110
  };
113
111
 
114
112
  const AttachmentUI: FC = () => {
115
- const aui = useAui();
116
- const isComposer = aui.attachment.source !== "message";
117
- const src = useAttachmentSrc();
118
-
119
- const isImage = useAuiState((s) => s.attachment.type === "image");
120
- const name = useAuiState((s) => s.attachment.name);
121
- const typeLabel = useAuiState((s) => {
122
- const type = s.attachment.type;
123
- switch (type) {
124
- case "image":
125
- return "Image";
126
- case "document":
127
- return "Document";
128
- case "file":
129
- return "File";
130
- default:
131
- return type;
132
- }
133
- });
134
-
135
- // An attachment on a submission is still being prepared, whether or not the
136
- // adapter reports progress while it uploads.
137
- const uploadState = useAuiState((s) =>
138
- s.attachment.status.type === "incomplete" &&
139
- s.attachment.status.reason === "error"
140
- ? "error"
141
- : s.attachment.status.type === "running" ||
142
- (s.optional.message?.submission !== undefined &&
143
- s.attachment.status.type !== "complete")
144
- ? "uploading"
145
- : undefined,
146
- );
147
- const isUploading = uploadState === "uploading";
148
- const isError = uploadState === "error";
149
-
150
- const errorMessage = useAuiState((s) =>
151
- s.attachment.status.type === "incomplete" &&
152
- s.attachment.status.reason === "error"
153
- ? (s.attachment.status.message ?? "Upload failed")
154
- : undefined,
155
- );
113
+ const {
114
+ isComposer,
115
+ src,
116
+ isImage,
117
+ name,
118
+ typeLabel,
119
+ isUploading,
120
+ isError,
121
+ errorMessage,
122
+ } = useAttachmentState();
156
123
 
157
124
  return (
158
125
  <TooltipProvider>
@@ -13,7 +13,7 @@
13
13
  "typecheck": "tsc --noEmit"
14
14
  },
15
15
  "dependencies": {
16
- "@ai-sdk/openai": "^4.0.86",
16
+ "@ai-sdk/openai": "^4.0.96",
17
17
  "@assistant-ui/ai-sdk": "workspace:*",
18
18
  "@assistant-ui/core": "workspace:*",
19
19
  "@assistant-ui/react": "workspace:*",
@@ -21,16 +21,16 @@
21
21
  "@assistant-ui/react-markdown": "workspace:*",
22
22
  "@assistant-ui/store": "workspace:*",
23
23
  "@assistant-ui/tap": "workspace:*",
24
- "@base-ui/react": "^1.8.0",
25
- "ai": "^7.0.130",
24
+ "@base-ui/react": "^1.9.0",
25
+ "ai": "^7.0.143",
26
26
  "assistant-cloud": "workspace:*",
27
27
  "class-variance-authority": "^0.7.1",
28
- "cn": "^0.4.0",
28
+ "cn": "^0.5.0",
29
29
  "harness-sdk": "file:vendor/harness-sdk-0.3.1.tgz",
30
- "lucide-react": "^1.52.0",
31
- "next": "^16.4.1",
32
- "react": "^19.3.0",
33
- "react-dom": "^19.3.0",
30
+ "lucide-react": "^1.59.0",
31
+ "next": "^16.4.2",
32
+ "react": "^19.3.1",
33
+ "react-dom": "^19.3.1",
34
34
  "remark-gfm": "^4.0.1",
35
35
  "statewire": "file:vendor/statewire-0.19.3.tgz",
36
36
  "tw-animate-css": "^1.4.0",
@@ -40,11 +40,11 @@
40
40
  "devDependencies": {
41
41
  "@assistant-ui/next": "workspace:*",
42
42
  "@tailwindcss/postcss": "^4.3.3",
43
- "@types/node": "^26.6.4",
43
+ "@types/node": "^26.6.5",
44
44
  "@types/react": "^19.3.0",
45
45
  "@types/react-dom": "^19.3.0",
46
- "oxfmt": "^0.72.0",
47
- "oxlint": "^1.87.0",
46
+ "oxfmt": "^0.73.0",
47
+ "oxlint": "^1.88.0",
48
48
  "tailwindcss": "^4.3.3",
49
49
  "typescript": "^7.0.2"
50
50
  }
@@ -1,42 +0,0 @@
1
- # See https://help.github.com/articles/ignoring-files/ for more about ignoring files.
2
-
3
- # dependencies
4
- /node_modules
5
- /.pnp
6
- .pnp.*
7
- .yarn/*
8
- !.yarn/patches
9
- !.yarn/plugins
10
- !.yarn/releases
11
- !.yarn/versions
12
-
13
- # testing
14
- /coverage
15
-
16
- # next.js
17
- /.next/
18
- /out/
19
-
20
- # production
21
- /build
22
-
23
- # misc
24
- .DS_Store
25
- *.pem
26
-
27
- # debug
28
- npm-debug.log*
29
- yarn-debug.log*
30
- yarn-error.log*
31
- .pnpm-debug.log*
32
-
33
- # env files (can opt-in for committing if needed)
34
- .env*
35
- !.env.example
36
-
37
- # vercel
38
- .vercel
39
-
40
- # typescript
41
- *.tsbuildinfo
42
- next-env.d.ts