@chat-js/cli 0.3.0 → 0.6.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (136) hide show
  1. package/dist/index.js +1173 -964
  2. package/package.json +1 -1
  3. package/templates/chat-app/app/(auth)/device-login/page.tsx +37 -0
  4. package/templates/chat-app/app/(auth)/login/page.tsx +26 -2
  5. package/templates/chat-app/app/(auth)/register/page.tsx +0 -12
  6. package/templates/chat-app/app/(chat)/api/chat/filter-reasoning-parts.ts +1 -1
  7. package/templates/chat-app/app/(chat)/api/chat/prepare/route.ts +94 -0
  8. package/templates/chat-app/app/(chat)/api/chat/route.ts +107 -16
  9. package/templates/chat-app/app/(chat)/layout.tsx +4 -1
  10. package/templates/chat-app/app/api/trpc/[trpc]/route.ts +1 -0
  11. package/templates/chat-app/app/globals.css +9 -9
  12. package/templates/chat-app/app/layout.tsx +4 -2
  13. package/templates/chat-app/biome.jsonc +3 -3
  14. package/templates/chat-app/chat.config.ts +32 -12
  15. package/templates/chat-app/components/ai-elements/prompt-input.tsx +1 -1
  16. package/templates/chat-app/components/anonymous-session-init.tsx +10 -6
  17. package/templates/chat-app/components/artifact-actions.tsx +81 -18
  18. package/templates/chat-app/components/artifact-panel.tsx +142 -41
  19. package/templates/chat-app/components/attachment-list.tsx +1 -1
  20. package/templates/chat-app/components/{social-auth-providers.tsx → auth-providers.tsx} +49 -4
  21. package/templates/chat-app/components/chat/chat-welcome.tsx +3 -3
  22. package/templates/chat-app/components/chat-menu-items.tsx +1 -1
  23. package/templates/chat-app/components/chat-sync.tsx +9 -11
  24. package/templates/chat-app/components/console.tsx +9 -9
  25. package/templates/chat-app/components/context-usage.tsx +2 -2
  26. package/templates/chat-app/components/create-artifact.tsx +15 -5
  27. package/templates/chat-app/components/data-stream-handler.tsx +57 -16
  28. package/templates/chat-app/components/device-login-page.tsx +191 -0
  29. package/templates/chat-app/components/diffview.tsx +8 -2
  30. package/templates/chat-app/components/electron-auth-handler.tsx +184 -0
  31. package/templates/chat-app/components/electron-auth-ui.tsx +121 -0
  32. package/templates/chat-app/components/favicon-group.tsx +1 -1
  33. package/templates/chat-app/components/feedback-actions.tsx +7 -3
  34. package/templates/chat-app/components/greeting.tsx +1 -1
  35. package/templates/chat-app/components/interactive-chart-impl.tsx +3 -4
  36. package/templates/chat-app/components/interactive-charts.tsx +1 -1
  37. package/templates/chat-app/components/login-form.tsx +52 -10
  38. package/templates/chat-app/components/message-editor.tsx +7 -3
  39. package/templates/chat-app/components/message-siblings.tsx +14 -1
  40. package/templates/chat-app/components/model-selector.tsx +295 -27
  41. package/templates/chat-app/components/multimodal-input.tsx +259 -22
  42. package/templates/chat-app/components/parallel-response-cards.tsx +175 -0
  43. package/templates/chat-app/components/part/code-execution.tsx +8 -2
  44. package/templates/chat-app/components/part/document-common.tsx +1 -1
  45. package/templates/chat-app/components/part/document-preview.tsx +5 -5
  46. package/templates/chat-app/components/part/retrieve-url.tsx +12 -12
  47. package/templates/chat-app/components/part/text-message-part.tsx +9 -1
  48. package/templates/chat-app/components/project-chat-item.tsx +1 -1
  49. package/templates/chat-app/components/project-menu-items.tsx +1 -1
  50. package/templates/chat-app/components/research-task.tsx +1 -1
  51. package/templates/chat-app/components/research-tasks.tsx +1 -1
  52. package/templates/chat-app/components/retry-button.tsx +25 -8
  53. package/templates/chat-app/components/sandbox.tsx +1 -1
  54. package/templates/chat-app/components/sheet-editor.tsx +7 -7
  55. package/templates/chat-app/components/sidebar-chats-list.tsx +1 -1
  56. package/templates/chat-app/components/sidebar-toggle.tsx +15 -2
  57. package/templates/chat-app/components/sidebar-top-row.tsx +27 -12
  58. package/templates/chat-app/components/sidebar-user-nav.tsx +10 -1
  59. package/templates/chat-app/components/signup-form.tsx +49 -10
  60. package/templates/chat-app/components/sources.tsx +4 -4
  61. package/templates/chat-app/components/text-editor.tsx +5 -2
  62. package/templates/chat-app/components/toolbar.tsx +3 -3
  63. package/templates/chat-app/components/ui/sidebar.tsx +0 -1
  64. package/templates/chat-app/components/upgrade-cta/limit-display.tsx +1 -1
  65. package/templates/chat-app/components/user-message.tsx +14 -2
  66. package/templates/chat-app/electron.d.ts +41 -0
  67. package/templates/chat-app/evals/my-eval.eval.ts +3 -1
  68. package/templates/chat-app/hooks/chat-sync-hooks.ts +11 -0
  69. package/templates/chat-app/hooks/use-artifact.tsx +13 -13
  70. package/templates/chat-app/hooks/use-navigate-to-message.ts +39 -0
  71. package/templates/chat-app/lib/ai/gateways/provider-types.ts +19 -10
  72. package/templates/chat-app/lib/ai/stream-errors.test.ts +72 -0
  73. package/templates/chat-app/lib/ai/stream-errors.ts +94 -0
  74. package/templates/chat-app/lib/ai/tools/code-execution.javascript.ts +171 -0
  75. package/templates/chat-app/lib/ai/tools/code-execution.python.ts +336 -0
  76. package/templates/chat-app/lib/ai/tools/code-execution.shared.test.ts +71 -0
  77. package/templates/chat-app/lib/ai/tools/code-execution.shared.ts +59 -0
  78. package/templates/chat-app/lib/ai/tools/code-execution.ts +62 -391
  79. package/templates/chat-app/lib/ai/tools/code-execution.types.ts +24 -0
  80. package/templates/chat-app/lib/ai/tools/steps/multi-query-web-search.ts +3 -2
  81. package/templates/chat-app/lib/ai/types.ts +74 -3
  82. package/templates/chat-app/lib/anonymous-session-client.ts +0 -3
  83. package/templates/chat-app/lib/artifacts/code/client.tsx +35 -5
  84. package/templates/chat-app/lib/artifacts/sheet/client.tsx +11 -3
  85. package/templates/chat-app/lib/auth-client.ts +23 -1
  86. package/templates/chat-app/lib/auth.ts +18 -1
  87. package/templates/chat-app/lib/blob.ts +1 -1
  88. package/templates/chat-app/lib/clone-messages.ts +1 -1
  89. package/templates/chat-app/lib/config-schema.ts +18 -1
  90. package/templates/chat-app/lib/constants.ts +3 -4
  91. package/templates/chat-app/lib/db/migrations/0044_gray_red_shift.sql +5 -0
  92. package/templates/chat-app/lib/db/migrations/meta/0044_snapshot.json +1480 -0
  93. package/templates/chat-app/lib/db/migrations/meta/_journal.json +7 -0
  94. package/templates/chat-app/lib/db/queries.ts +84 -4
  95. package/templates/chat-app/lib/db/schema.ts +4 -1
  96. package/templates/chat-app/lib/editor/config.ts +4 -4
  97. package/templates/chat-app/lib/electron-auth.ts +96 -0
  98. package/templates/chat-app/lib/env-schema.ts +33 -4
  99. package/templates/chat-app/lib/message-conversion.ts +14 -2
  100. package/templates/chat-app/lib/playwright-test-environment.ts +18 -0
  101. package/templates/chat-app/lib/social-auth.ts +5 -0
  102. package/templates/chat-app/lib/stores/hooks-threads.ts +38 -1
  103. package/templates/chat-app/lib/stores/with-threads.test.ts +137 -0
  104. package/templates/chat-app/lib/stores/with-threads.ts +159 -7
  105. package/templates/chat-app/lib/stores/with-tracing.ts +1 -1
  106. package/templates/chat-app/lib/thread-utils.ts +22 -3
  107. package/templates/chat-app/lib/utils/download-assets.ts +6 -7
  108. package/templates/chat-app/lib/utils/rate-limit.ts +9 -3
  109. package/templates/chat-app/package.json +20 -18
  110. package/templates/chat-app/playwright.config.ts +0 -19
  111. package/templates/chat-app/providers/chat-input-provider.tsx +40 -2
  112. package/templates/chat-app/proxy.ts +28 -3
  113. package/templates/chat-app/scripts/check-env.ts +10 -0
  114. package/templates/chat-app/scripts/db-branch-delete.sh +7 -1
  115. package/templates/chat-app/scripts/db-branch-use.sh +7 -1
  116. package/templates/chat-app/scripts/with-db.sh +7 -1
  117. package/templates/chat-app/trpc/server.tsx +7 -2
  118. package/templates/chat-app/tsconfig.json +2 -1
  119. package/templates/chat-app/vercel.json +0 -10
  120. package/templates/chat-app/vitest.config.ts +2 -0
  121. package/templates/electron/CHANGELOG.md +7 -0
  122. package/templates/electron/README.md +54 -0
  123. package/templates/electron/entitlements.mac.plist +10 -0
  124. package/templates/electron/forge.config.ts +157 -0
  125. package/templates/electron/icon.png +0 -0
  126. package/templates/electron/package.json +53 -0
  127. package/templates/electron/scripts/generate-icons.test.js +37 -0
  128. package/templates/electron/scripts/generate-icons.ts +29 -0
  129. package/templates/electron/scripts/run-forge.cjs +28 -0
  130. package/templates/electron/scripts/write-branding.ts +18 -0
  131. package/templates/electron/src/config.ts +16 -0
  132. package/templates/electron/src/lib/auth-client.ts +64 -0
  133. package/templates/electron/src/main.ts +670 -0
  134. package/templates/electron/src/preload.d.ts +27 -0
  135. package/templates/electron/src/preload.ts +25 -0
  136. package/templates/electron/tsconfig.json +18 -0
@@ -6,7 +6,7 @@ import {
6
6
  type ConsoleOutput,
7
7
  type ConsoleOutputContent,
8
8
  } from "@/components/console";
9
- import { Artifact } from "@/components/create-artifact";
9
+ import { Artifact, type ArtifactMetadata } from "@/components/create-artifact";
10
10
  import { config } from "@/lib/config";
11
11
  import { generateUUID, getLanguageFromFileName } from "@/lib/utils";
12
12
 
@@ -56,12 +56,36 @@ function detectRequiredHandlers(code: string): string[] {
56
56
  return handlers;
57
57
  }
58
58
 
59
- interface Metadata {
59
+ export interface CodeArtifactMetadata {
60
60
  language: string;
61
61
  outputs: ConsoleOutput[];
62
62
  }
63
63
 
64
- export const codeArtifact = new Artifact<"code", Metadata>({
64
+ export function isCodeArtifactMetadata(
65
+ metadata: ArtifactMetadata
66
+ ): metadata is CodeArtifactMetadata {
67
+ return (
68
+ metadata !== null &&
69
+ typeof metadata === "object" &&
70
+ "language" in metadata &&
71
+ typeof metadata.language === "string" &&
72
+ "outputs" in metadata &&
73
+ Array.isArray(metadata.outputs)
74
+ );
75
+ }
76
+
77
+ export function getCodeArtifactMetadata(
78
+ metadata: ArtifactMetadata
79
+ ): CodeArtifactMetadata {
80
+ return isCodeArtifactMetadata(metadata)
81
+ ? metadata
82
+ : {
83
+ language: "python",
84
+ outputs: [],
85
+ };
86
+ }
87
+
88
+ export const codeArtifact = new Artifact<"code", CodeArtifactMetadata>({
65
89
  kind: "code",
66
90
  description:
67
91
  "Useful for code generation; Code execution is only available for Python code.",
@@ -184,14 +208,20 @@ export const codeArtifact = new Artifact<"code", Metadata>({
184
208
  },
185
209
  ],
186
210
  }));
187
- } catch (error: any) {
211
+ } catch (error: unknown) {
188
212
  setMetadata((metadata) => ({
189
213
  ...metadata,
190
214
  outputs: [
191
215
  ...metadata.outputs.filter((output) => output.id !== runId),
192
216
  {
193
217
  id: runId,
194
- contents: [{ type: "text", value: error.message }],
218
+ contents: [
219
+ {
220
+ type: "text",
221
+ value:
222
+ error instanceof Error ? error.message : String(error),
223
+ },
224
+ ],
195
225
  status: "failed",
196
226
  },
197
227
  ],
@@ -1,13 +1,21 @@
1
1
  import { Copy, LineChart, Redo2, Sparkles, Undo2 } from "lucide-react";
2
2
  import { parse, unparse } from "papaparse";
3
3
  import { toast } from "sonner";
4
- import { Artifact } from "@/components/create-artifact";
4
+ import { Artifact, type ArtifactMetadata } from "@/components/create-artifact";
5
5
  import { SpreadsheetEditor } from "@/components/sheet-editor";
6
6
  import { config } from "@/lib/config";
7
7
 
8
- type Metadata = any;
8
+ export type SheetArtifactMetadata = Record<string, unknown>;
9
9
 
10
- export const sheetArtifact = new Artifact<"sheet", Metadata>({
10
+ export function getSheetArtifactMetadata(
11
+ metadata: ArtifactMetadata
12
+ ): SheetArtifactMetadata {
13
+ return metadata && typeof metadata === "object"
14
+ ? Object.fromEntries(Object.entries(metadata))
15
+ : {};
16
+ }
17
+
18
+ export const sheetArtifact = new Artifact<"sheet", SheetArtifactMetadata>({
11
19
  kind: "sheet",
12
20
  description: "Useful for working with spreadsheets",
13
21
  initialize: async () => {
@@ -1,10 +1,32 @@
1
+ import { electronProxyClient } from "@better-auth/electron/proxy";
1
2
  import { nextCookies } from "better-auth/next-js";
2
3
  import { createAuthClient } from "better-auth/react";
4
+ import { config } from "@/lib/config";
5
+ import {
6
+ ELECTRON_APP_SCHEME,
7
+ ELECTRON_AUTH_CALLBACK_PATH,
8
+ ELECTRON_AUTH_CLIENT_ID,
9
+ ELECTRON_AUTH_COOKIE_PREFIX,
10
+ } from "@/lib/electron-auth";
3
11
 
4
12
  // Better Auth auto-detects the base URL from window.location.origin on client
5
13
  // and uses relative URLs for SSR, so we don't need to specify baseURL
6
14
  const authClient = createAuthClient({
7
- plugins: [nextCookies()],
15
+ plugins: [
16
+ nextCookies(),
17
+ ...(config.desktopApp.enabled
18
+ ? [
19
+ electronProxyClient({
20
+ callbackPath: ELECTRON_AUTH_CALLBACK_PATH,
21
+ clientID: ELECTRON_AUTH_CLIENT_ID,
22
+ cookiePrefix: ELECTRON_AUTH_COOKIE_PREFIX,
23
+ protocol: {
24
+ scheme: ELECTRON_APP_SCHEME,
25
+ },
26
+ }),
27
+ ]
28
+ : []),
29
+ ],
8
30
  });
9
31
 
10
32
  export default authClient;
@@ -1,3 +1,4 @@
1
+ import { electron } from "@better-auth/electron";
1
2
  import { betterAuth } from "better-auth";
2
3
  import { drizzleAdapter } from "better-auth/adapters/drizzle";
3
4
  import { nextCookies } from "better-auth/next-js";
@@ -5,6 +6,11 @@ import { env } from "@/lib/env";
5
6
  import { config } from "./config";
6
7
  import { db } from "./db/client";
7
8
  import { schema } from "./db/schema";
9
+ import {
10
+ ELECTRON_AUTH_CLIENT_ID,
11
+ ELECTRON_AUTH_COOKIE_PREFIX,
12
+ ELECTRON_TRUSTED_ORIGINS,
13
+ } from "./electron-auth";
8
14
 
9
15
  export const auth = betterAuth({
10
16
  database: drizzleAdapter(db, {
@@ -16,6 +22,7 @@ export const auth = betterAuth({
16
22
  // Vercel URL for preview branches
17
23
  ...(env.VERCEL_URL ? [`https://${env.VERCEL_URL}`] : []),
18
24
  config.appUrl,
25
+ ...(config.desktopApp.enabled ? ELECTRON_TRUSTED_ORIGINS : []),
19
26
  ],
20
27
  secret: env.AUTH_SECRET,
21
28
 
@@ -60,7 +67,17 @@ export const auth = betterAuth({
60
67
 
61
68
  return { google, github, vercel } as const;
62
69
  })(),
63
- plugins: [nextCookies()],
70
+ plugins: [
71
+ nextCookies(),
72
+ ...(config.desktopApp.enabled
73
+ ? [
74
+ electron({
75
+ clientID: ELECTRON_AUTH_CLIENT_ID,
76
+ cookiePrefix: ELECTRON_AUTH_COOKIE_PREFIX,
77
+ }),
78
+ ]
79
+ : []),
80
+ ],
64
81
  });
65
82
 
66
83
  // Infer session type from the auth instance for type safety
@@ -67,7 +67,7 @@ export function extractFilenameFromUrl(url: string): string | null {
67
67
 
68
68
  // Remove the prefix if it exists in the URL
69
69
  if (filename.startsWith(BLOB_FILE_PREFIX)) {
70
- return filename.substring(BLOB_FILE_PREFIX.length);
70
+ return filename.slice(BLOB_FILE_PREFIX.length);
71
71
  }
72
72
 
73
73
  return filename;
@@ -334,7 +334,7 @@ export function cloneMessagesWithDocuments<
334
334
  messageId: string;
335
335
  userId: string;
336
336
  title: string;
337
- kind: any;
337
+ kind: unknown;
338
338
  content: string | null;
339
339
  createdAt: Date;
340
340
  },
@@ -224,9 +224,14 @@ export const featuresConfigSchema = z
224
224
  attachments: z
225
225
  .boolean()
226
226
  .describe("File attachments (requires BLOB_READ_WRITE_TOKEN)"),
227
+ parallelResponses: z
228
+ .boolean()
229
+ .default(true)
230
+ .describe("Send one message to multiple models simultaneously"),
227
231
  })
228
232
  .default({
229
233
  attachments: false,
234
+ parallelResponses: true,
230
235
  });
231
236
 
232
237
  export const authenticationConfigSchema = z
@@ -249,6 +254,16 @@ export const authenticationConfigSchema = z
249
254
  vercel: false,
250
255
  });
251
256
 
257
+ export const desktopAppConfigSchema = z
258
+ .object({
259
+ enabled: z
260
+ .boolean()
261
+ .describe("Enable Electron desktop auth/runtime integration"),
262
+ })
263
+ .default({
264
+ enabled: false,
265
+ });
266
+
252
267
  export const configSchema = z.object({
253
268
  appPrefix: z.string().default("chatjs"),
254
269
  appName: z.string().default("My AI Chat"),
@@ -321,6 +336,8 @@ export const configSchema = z.object({
321
336
 
322
337
  authentication: authenticationConfigSchema,
323
338
 
339
+ desktopApp: desktopAppConfigSchema,
340
+
324
341
  ai: aiConfigSchema,
325
342
 
326
343
  anonymous: anonymousConfigSchema,
@@ -336,6 +353,7 @@ export type AnonymousConfig = z.infer<typeof anonymousConfigSchema>;
336
353
  export type AttachmentsConfig = z.infer<typeof attachmentsConfigSchema>;
337
354
  export type FeaturesConfig = z.infer<typeof featuresConfigSchema>;
338
355
  export type AuthenticationConfig = z.infer<typeof authenticationConfigSchema>;
356
+ export type DesktopAppConfig = z.infer<typeof desktopAppConfigSchema>;
339
357
 
340
358
  // Gateway-aware input types: model IDs narrowed per gateway for autocomplete
341
359
  type ZodConfigInput = z.input<typeof configSchema>;
@@ -384,7 +402,6 @@ interface AiToolsInputFor<G extends GatewayType> {
384
402
  }
385
403
 
386
404
  // Only gateway is required; everything else is an override on top of GATEWAY_MODEL_DEFAULTS
387
- // biome-ignore lint/style/useConsistentTypeDefinitions: type is used intentionally here
388
405
  type AiInputFor<G extends GatewayType> = {
389
406
  gateway: G;
390
407
  providerOrder?: AiShape["providerOrder"];
@@ -1,11 +1,10 @@
1
1
  import { config } from "@/lib/config";
2
+ import { isPlaywrightTestEnvironment as getIsPlaywrightTestEnvironment } from "@/lib/playwright-test-environment";
2
3
 
3
4
  const _isProductionEnvironment = process.env.NODE_ENV === "production";
4
5
 
5
- const _isTestEnvironment = Boolean(
6
- process.env.PLAYWRIGHT_TEST_BASE_URL ||
7
- process.env.PLAYWRIGHT ||
8
- process.env.CI_PLAYWRIGHT
6
+ export const isPlaywrightTestEnvironment = getIsPlaywrightTestEnvironment(
7
+ process.env
9
8
  );
10
9
 
11
10
  export const BLOB_FILE_PREFIX = `${config.appPrefix}/files/`;
@@ -0,0 +1,5 @@
1
+ ALTER TABLE "Message" ALTER COLUMN "selectedModel" DROP DEFAULT;--> statement-breakpoint
2
+ ALTER TABLE "Message" ALTER COLUMN "selectedModel" SET DATA TYPE json USING to_json("selectedModel");--> statement-breakpoint
3
+ ALTER TABLE "Message" ADD COLUMN "parallelGroupId" uuid;--> statement-breakpoint
4
+ ALTER TABLE "Message" ADD COLUMN "parallelIndex" integer;--> statement-breakpoint
5
+ ALTER TABLE "Message" ADD COLUMN "isPrimaryParallel" boolean;--> statement-breakpoint