veryfront 0.0.47 → 0.0.48

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 (38) hide show
  1. package/dist/ai/index.js +11 -5
  2. package/dist/ai/index.js.map +2 -2
  3. package/dist/cli.js +269 -69
  4. package/dist/components.js +1 -1
  5. package/dist/components.js.map +1 -1
  6. package/dist/config.js +1 -1
  7. package/dist/config.js.map +1 -1
  8. package/dist/data.js +1 -1
  9. package/dist/data.js.map +1 -1
  10. package/dist/index.js +5 -2
  11. package/dist/index.js.map +2 -2
  12. package/dist/integrations/_base/files/app/api/auth/status/route.ts +30 -0
  13. package/dist/integrations/_base/files/app/components/ServiceConnections.tsx +153 -0
  14. package/dist/integrations/_base/files/lib/token-store.ts +5 -1
  15. package/dist/integrations/calendar/connector.json +7 -1
  16. package/dist/integrations/calendar/files/_env.example +29 -0
  17. package/dist/integrations/calendar/files/ai/tools/create-event.ts +2 -6
  18. package/dist/integrations/calendar/files/ai/tools/find-free-time.ts +2 -6
  19. package/dist/integrations/calendar/files/ai/tools/list-events.ts +2 -6
  20. package/dist/integrations/calendar/files/lib/token-store.ts +5 -1
  21. package/dist/integrations/github/files/ai/tools/create-issue.ts +2 -6
  22. package/dist/integrations/github/files/ai/tools/get-pr-diff.ts +2 -6
  23. package/dist/integrations/github/files/ai/tools/list-prs.ts +2 -6
  24. package/dist/integrations/github/files/ai/tools/list-repos.ts +2 -6
  25. package/dist/integrations/github/files/lib/token-store.ts +5 -1
  26. package/dist/integrations/gmail/connector.json +7 -1
  27. package/dist/integrations/gmail/files/_env.example +29 -0
  28. package/dist/integrations/gmail/files/ai/tools/list-emails.ts +2 -6
  29. package/dist/integrations/gmail/files/ai/tools/search-emails.ts +2 -6
  30. package/dist/integrations/gmail/files/ai/tools/send-email.ts +2 -6
  31. package/dist/integrations/gmail/files/lib/token-store.ts +5 -1
  32. package/dist/integrations/slack/files/ai/tools/get-messages.ts +2 -6
  33. package/dist/integrations/slack/files/ai/tools/list-channels.ts +2 -6
  34. package/dist/integrations/slack/files/ai/tools/send-message.ts +2 -6
  35. package/dist/integrations/slack/files/lib/token-store.ts +5 -1
  36. package/dist/templates/ai/app/api/chat/route.ts +8 -1
  37. package/dist/templates/ai/app/page.tsx +3 -2
  38. package/package.json +1 -1
@@ -0,0 +1,30 @@
1
+ import { tokenStore } from "../../../../lib/token-store.ts";
2
+
3
+ // Services to check - add/remove based on your integrations
4
+ // Gmail and Calendar share OAuth credentials, so we check both separately
5
+ const SERVICES = [
6
+ { id: "gmail", name: "Gmail" },
7
+ { id: "calendar", name: "Calendar" },
8
+ // { id: 'slack', name: 'Slack' },
9
+ // { id: 'github', name: 'GitHub' },
10
+ ];
11
+
12
+ export async function GET() {
13
+ // In production, get userId from session/cookie
14
+ // For development, we use a default user
15
+ const userId = "current-user";
16
+
17
+ const services: Record<string, boolean> = {};
18
+
19
+ for (const service of SERVICES) {
20
+ try {
21
+ services[service.id] = await tokenStore.isConnected(userId, service.id);
22
+ } catch {
23
+ services[service.id] = false;
24
+ }
25
+ }
26
+
27
+ return new Response(JSON.stringify({ services }), {
28
+ headers: { "Content-Type": "application/json" },
29
+ });
30
+ }
@@ -0,0 +1,153 @@
1
+ "use client";
2
+
3
+ import { useEffect, useState } from "react";
4
+
5
+ interface Service {
6
+ id: string;
7
+ name: string;
8
+ connected: boolean;
9
+ authUrl: string;
10
+ }
11
+
12
+ interface ServiceConnectionsProps {
13
+ services: Array<{
14
+ id: string;
15
+ name: string;
16
+ authUrl: string;
17
+ }>;
18
+ className?: string;
19
+ }
20
+
21
+ export function ServiceConnections({ services, className = "" }: ServiceConnectionsProps) {
22
+ const [status, setStatus] = useState<Record<string, boolean>>({});
23
+ const [loading, setLoading] = useState(true);
24
+
25
+ useEffect(() => {
26
+ async function checkStatus() {
27
+ try {
28
+ const res = await fetch("/api/auth/status");
29
+ if (res.ok) {
30
+ const data = await res.json();
31
+ setStatus(data.services || {});
32
+ }
33
+ } catch (err) {
34
+ console.error("Failed to check service status:", err);
35
+ } finally {
36
+ setLoading(false);
37
+ }
38
+ }
39
+ checkStatus();
40
+ }, []);
41
+
42
+ const servicesWithStatus: Service[] = services.map((s) => ({
43
+ ...s,
44
+ connected: status[s.id] ?? false,
45
+ }));
46
+
47
+ const connectedCount = servicesWithStatus.filter((s) => s.connected).length;
48
+
49
+ if (loading) {
50
+ return (
51
+ <div className={`flex items-center gap-2 ${className}`}>
52
+ <div className="animate-pulse h-6 w-32 bg-neutral-200 dark:bg-neutral-700 rounded" />
53
+ </div>
54
+ );
55
+ }
56
+
57
+ return (
58
+ <div className={`flex items-center gap-2 ${className}`}>
59
+ {servicesWithStatus.map((service) => <ServiceBadge key={service.id} service={service} />)}
60
+ {connectedCount < services.length && (
61
+ <span className="text-xs text-neutral-500 dark:text-neutral-400 ml-1">
62
+ {connectedCount}/{services.length} connected
63
+ </span>
64
+ )}
65
+ </div>
66
+ );
67
+ }
68
+
69
+ function ServiceBadge({ service }: { service: Service }) {
70
+ const handleConnect = () => {
71
+ window.location.href = service.authUrl;
72
+ };
73
+
74
+ if (service.connected) {
75
+ return (
76
+ <span
77
+ className="inline-flex items-center gap-1.5 px-2.5 py-1 rounded-full text-xs font-medium bg-green-100 text-green-800 dark:bg-green-900/30 dark:text-green-400"
78
+ title={`${service.name} connected`}
79
+ >
80
+ <span className="w-1.5 h-1.5 rounded-full bg-green-500" />
81
+ {service.name}
82
+ </span>
83
+ );
84
+ }
85
+
86
+ return (
87
+ <button
88
+ onClick={handleConnect}
89
+ className="inline-flex items-center gap-1.5 px-2.5 py-1 rounded-full text-xs font-medium bg-neutral-100 text-neutral-600 hover:bg-neutral-200 dark:bg-neutral-800 dark:text-neutral-400 dark:hover:bg-neutral-700 transition-colors"
90
+ title={`Connect ${service.name}`}
91
+ >
92
+ <span className="w-1.5 h-1.5 rounded-full bg-neutral-400" />
93
+ {service.name}
94
+ </button>
95
+ );
96
+ }
97
+
98
+ export function ServiceConnectionsCard({ services, className = "" }: ServiceConnectionsProps) {
99
+ const [status, setStatus] = useState<Record<string, boolean>>({});
100
+ const [loading, setLoading] = useState(true);
101
+
102
+ useEffect(() => {
103
+ async function checkStatus() {
104
+ try {
105
+ const res = await fetch("/api/auth/status");
106
+ if (res.ok) {
107
+ const data = await res.json();
108
+ setStatus(data.services || {});
109
+ }
110
+ } catch (err) {
111
+ console.error("Failed to check service status:", err);
112
+ } finally {
113
+ setLoading(false);
114
+ }
115
+ }
116
+ checkStatus();
117
+ }, []);
118
+
119
+ const servicesWithStatus: Service[] = services.map((s) => ({
120
+ ...s,
121
+ connected: status[s.id] ?? false,
122
+ }));
123
+
124
+ const disconnectedServices = servicesWithStatus.filter((s) => !s.connected);
125
+
126
+ if (loading || disconnectedServices.length === 0) {
127
+ return null;
128
+ }
129
+
130
+ return (
131
+ <div
132
+ className={`rounded-lg border border-amber-200 dark:border-amber-900/50 bg-amber-50 dark:bg-amber-900/20 p-4 ${className}`}
133
+ >
134
+ <h3 className="font-medium text-amber-900 dark:text-amber-200 mb-2">
135
+ Connect your services
136
+ </h3>
137
+ <p className="text-sm text-amber-700 dark:text-amber-300/80 mb-3">
138
+ Connect the following services to unlock all features:
139
+ </p>
140
+ <div className="flex flex-wrap gap-2">
141
+ {disconnectedServices.map((service) => (
142
+ <a
143
+ key={service.id}
144
+ href={service.authUrl}
145
+ className="inline-flex items-center gap-2 px-3 py-1.5 rounded-md text-sm font-medium bg-amber-100 text-amber-800 hover:bg-amber-200 dark:bg-amber-900/40 dark:text-amber-200 dark:hover:bg-amber-900/60 transition-colors"
146
+ >
147
+ Connect {service.name}
148
+ </a>
149
+ ))}
150
+ </div>
151
+ </div>
152
+ );
153
+ }
@@ -21,7 +21,11 @@ export interface TokenStore {
21
21
  }
22
22
 
23
23
  // In-memory storage for development
24
- const tokens = new Map<string, OAuthToken>();
24
+ // Use globalThis to share across esbuild bundles (each API route is bundled separately)
25
+ const TOKENS_KEY = "__veryfront_oauth_tokens__";
26
+ // deno-lint-ignore no-explicit-any
27
+ const globalStore = globalThis as any;
28
+ const tokens: Map<string, OAuthToken> = globalStore[TOKENS_KEY] ||= new Map<string, OAuthToken>();
25
29
 
26
30
  function getKey(userId: string, service: string): string {
27
31
  return `${userId}:${service}`;
@@ -12,7 +12,13 @@
12
12
  "https://www.googleapis.com/auth/calendar.readonly",
13
13
  "https://www.googleapis.com/auth/calendar.events"
14
14
  ],
15
- "callbackPath": "/api/auth/calendar/callback"
15
+ "callbackPath": "/api/auth/calendar/callback",
16
+ "requiredApis": [
17
+ {
18
+ "name": "Google Calendar API",
19
+ "enableUrl": "https://console.cloud.google.com/apis/library/calendar-json.googleapis.com"
20
+ }
21
+ ]
16
22
  },
17
23
  "envVars": [
18
24
  {
@@ -0,0 +1,29 @@
1
+ # =============================================================================
2
+ # Google Calendar Integration Setup
3
+ # =============================================================================
4
+ #
5
+ # STEP 1: Create a Google Cloud Project
6
+ # Visit: https://console.cloud.google.com/projectcreate
7
+ #
8
+ # STEP 2: Enable the Google Calendar API
9
+ # Visit: https://console.cloud.google.com/apis/library/calendar-json.googleapis.com
10
+ # Click "Enable" to activate the Calendar API for your project
11
+ #
12
+ # STEP 3: Configure OAuth Consent Screen
13
+ # Visit: https://console.cloud.google.com/apis/credentials/consent
14
+ # - Choose "External" user type (or "Internal" for Workspace)
15
+ # - Fill in app name, support email
16
+ # - Add scopes: calendar.readonly, calendar.events
17
+ # - Add your email as a test user (required for development)
18
+ #
19
+ # STEP 4: Create OAuth Credentials
20
+ # Visit: https://console.cloud.google.com/apis/credentials
21
+ # - Click "Create Credentials" > "OAuth client ID"
22
+ # - Application type: "Web application"
23
+ # - Add Authorized redirect URI: http://localhost:3000/api/auth/calendar/callback
24
+ # - Copy the Client ID and Client Secret below
25
+ #
26
+ # =============================================================================
27
+
28
+ GOOGLE_CLIENT_ID=your-client-id.apps.googleusercontent.com
29
+ GOOGLE_CLIENT_SECRET=your-client-secret
@@ -37,12 +37,8 @@ export default tool({
37
37
  { title, startTime, endTime, description, location, attendees, timeZone },
38
38
  context,
39
39
  ) => {
40
- const userId = context?.userId as string | undefined;
41
- if (!userId) {
42
- return {
43
- error: "User not authenticated. Please log in first.",
44
- };
45
- }
40
+ // Default to "current-user" for development; in production, always pass userId from session
41
+ const userId = (context?.userId as string | undefined) || "current-user";
46
42
 
47
43
  try {
48
44
  const calendar = createCalendarClient(userId);
@@ -24,12 +24,8 @@ export default tool({
24
24
  .describe("Only show slots during working hours (9 AM - 6 PM)"),
25
25
  }),
26
26
  execute: async ({ durationMinutes, daysToSearch, workingHoursOnly }, context) => {
27
- const userId = context?.userId as string | undefined;
28
- if (!userId) {
29
- return {
30
- error: "User not authenticated. Please log in first.",
31
- };
32
- }
27
+ // Default to "current-user" for development; in production, always pass userId from session
28
+ const userId = (context?.userId as string | undefined) || "current-user";
33
29
 
34
30
  try {
35
31
  const calendar = createCalendarClient(userId);
@@ -24,12 +24,8 @@ export default tool({
24
24
  .describe("Only show events for today"),
25
25
  }),
26
26
  execute: async ({ maxResults, daysAhead, todayOnly }, context) => {
27
- const userId = context?.userId as string | undefined;
28
- if (!userId) {
29
- return {
30
- error: "User not authenticated. Please log in first.",
31
- };
32
- }
27
+ // Default to "current-user" for development; in production, always pass userId from session
28
+ const userId = (context?.userId as string | undefined) || "current-user";
33
29
 
34
30
  try {
35
31
  const calendar = createCalendarClient(userId);
@@ -21,7 +21,11 @@ export interface TokenStore {
21
21
  }
22
22
 
23
23
  // In-memory storage for development
24
- const tokens = new Map<string, OAuthToken>();
24
+ // Use globalThis to share across esbuild bundles (each API route is bundled separately)
25
+ const TOKENS_KEY = "__veryfront_oauth_tokens__";
26
+ // deno-lint-ignore no-explicit-any
27
+ const globalStore = globalThis as any;
28
+ const tokens: Map<string, OAuthToken> = globalStore[TOKENS_KEY] ||= new Map<string, OAuthToken>();
25
29
 
26
30
  function getKey(userId: string, service: string): string {
27
31
  return `${userId}:${service}`;
@@ -27,12 +27,8 @@ export default tool({
27
27
  .describe("GitHub usernames to assign to the issue"),
28
28
  }),
29
29
  execute: async ({ repo, title, body, labels, assignees }, context) => {
30
- const userId = context?.userId as string | undefined;
31
- if (!userId) {
32
- return {
33
- error: "User not authenticated. Please log in first.",
34
- };
35
- }
30
+ // Default to "current-user" for development; in production, always pass userId from session
31
+ const userId = (context?.userId as string | undefined) || "current-user";
36
32
 
37
33
  const [owner, repoName] = repo.split("/");
38
34
  if (!owner || !repoName) {
@@ -16,12 +16,8 @@ export default tool({
16
16
  .describe("Pull request number"),
17
17
  }),
18
18
  execute: async ({ repo, prNumber }, context) => {
19
- const userId = context?.userId as string | undefined;
20
- if (!userId) {
21
- return {
22
- error: "User not authenticated. Please log in first.",
23
- };
24
- }
19
+ // Default to "current-user" for development; in production, always pass userId from session
20
+ const userId = (context?.userId as string | undefined) || "current-user";
25
21
 
26
22
  const [owner, repoName] = repo.split("/");
27
23
  if (!owner || !repoName) {
@@ -21,12 +21,8 @@ export default tool({
21
21
  .describe("Maximum number of pull requests to return"),
22
22
  }),
23
23
  execute: async ({ repo, state, limit }, context) => {
24
- const userId = context?.userId as string | undefined;
25
- if (!userId) {
26
- return {
27
- error: "User not authenticated. Please log in first.",
28
- };
29
- }
24
+ // Default to "current-user" for development; in production, always pass userId from session
25
+ const userId = (context?.userId as string | undefined) || "current-user";
30
26
 
31
27
  const [owner, repoName] = repo.split("/");
32
28
  if (!owner || !repoName) {
@@ -22,12 +22,8 @@ export default tool({
22
22
  .describe("Maximum number of repositories to return"),
23
23
  }),
24
24
  execute: async ({ type, sort, limit }, context) => {
25
- const userId = context?.userId as string | undefined;
26
- if (!userId) {
27
- return {
28
- error: "User not authenticated. Please log in first.",
29
- };
30
- }
25
+ // Default to "current-user" for development; in production, always pass userId from session
26
+ const userId = (context?.userId as string | undefined) || "current-user";
31
27
 
32
28
  try {
33
29
  const github = createGitHubClient(userId);
@@ -21,7 +21,11 @@ export interface TokenStore {
21
21
  }
22
22
 
23
23
  // In-memory storage for development
24
- const tokens = new Map<string, OAuthToken>();
24
+ // Use globalThis to share across esbuild bundles (each API route is bundled separately)
25
+ const TOKENS_KEY = "__veryfront_oauth_tokens__";
26
+ // deno-lint-ignore no-explicit-any
27
+ const globalStore = globalThis as any;
28
+ const tokens: Map<string, OAuthToken> = globalStore[TOKENS_KEY] ||= new Map<string, OAuthToken>();
25
29
 
26
30
  function getKey(userId: string, service: string): string {
27
31
  return `${userId}:${service}`;
@@ -13,7 +13,13 @@
13
13
  "https://www.googleapis.com/auth/gmail.send",
14
14
  "https://www.googleapis.com/auth/gmail.modify"
15
15
  ],
16
- "callbackPath": "/api/auth/gmail/callback"
16
+ "callbackPath": "/api/auth/gmail/callback",
17
+ "requiredApis": [
18
+ {
19
+ "name": "Gmail API",
20
+ "enableUrl": "https://console.cloud.google.com/apis/library/gmail.googleapis.com"
21
+ }
22
+ ]
17
23
  },
18
24
  "envVars": [
19
25
  {
@@ -0,0 +1,29 @@
1
+ # =============================================================================
2
+ # Gmail Integration Setup
3
+ # =============================================================================
4
+ #
5
+ # STEP 1: Create a Google Cloud Project
6
+ # Visit: https://console.cloud.google.com/projectcreate
7
+ #
8
+ # STEP 2: Enable the Gmail API
9
+ # Visit: https://console.cloud.google.com/apis/library/gmail.googleapis.com
10
+ # Click "Enable" to activate the Gmail API for your project
11
+ #
12
+ # STEP 3: Configure OAuth Consent Screen
13
+ # Visit: https://console.cloud.google.com/apis/credentials/consent
14
+ # - Choose "External" user type (or "Internal" for Workspace)
15
+ # - Fill in app name, support email
16
+ # - Add scopes: gmail.readonly, gmail.send, gmail.modify
17
+ # - Add your email as a test user (required for development)
18
+ #
19
+ # STEP 4: Create OAuth Credentials
20
+ # Visit: https://console.cloud.google.com/apis/credentials
21
+ # - Click "Create Credentials" > "OAuth client ID"
22
+ # - Application type: "Web application"
23
+ # - Add Authorized redirect URI: http://localhost:3000/api/auth/gmail/callback
24
+ # - Copy the Client ID and Client Secret below
25
+ #
26
+ # =============================================================================
27
+
28
+ GOOGLE_CLIENT_ID=your-client-id.apps.googleusercontent.com
29
+ GOOGLE_CLIENT_SECRET=your-client-secret
@@ -23,12 +23,8 @@ export default tool({
23
23
  .describe("Filter by Gmail label (e.g., 'INBOX', 'IMPORTANT', 'STARRED')"),
24
24
  }),
25
25
  execute: async ({ maxResults, unreadOnly, label }, context) => {
26
- const userId = context?.userId as string | undefined;
27
- if (!userId) {
28
- return {
29
- error: "User not authenticated. Please log in first.",
30
- };
31
- }
26
+ // Default to "current-user" for development; in production, always pass userId from session
27
+ const userId = (context?.userId as string | undefined) || "current-user";
32
28
 
33
29
  try {
34
30
  const gmail = createGmailClient(userId);
@@ -21,12 +21,8 @@ export default tool({
21
21
  .describe("Maximum number of results to return"),
22
22
  }),
23
23
  execute: async ({ query, maxResults }, context) => {
24
- const userId = context?.userId as string | undefined;
25
- if (!userId) {
26
- return {
27
- error: "User not authenticated. Please log in first.",
28
- };
29
- }
24
+ // Default to "current-user" for development; in production, always pass userId from session
25
+ const userId = (context?.userId as string | undefined) || "current-user";
30
26
 
31
27
  try {
32
28
  const gmail = createGmailClient(userId);
@@ -31,12 +31,8 @@ export default tool({
31
31
  .describe("Whether the body contains HTML"),
32
32
  }),
33
33
  execute: async ({ to, subject, body, cc, bcc, isHtml }, context) => {
34
- const userId = context?.userId as string | undefined;
35
- if (!userId) {
36
- return {
37
- error: "User not authenticated. Please log in first.",
38
- };
39
- }
34
+ // Default to "current-user" for development; in production, always pass userId from session
35
+ const userId = (context?.userId as string | undefined) || "current-user";
40
36
 
41
37
  try {
42
38
  const gmail = createGmailClient(userId);
@@ -21,7 +21,11 @@ export interface TokenStore {
21
21
  }
22
22
 
23
23
  // In-memory storage for development
24
- const tokens = new Map<string, OAuthToken>();
24
+ // Use globalThis to share across esbuild bundles (each API route is bundled separately)
25
+ const TOKENS_KEY = "__veryfront_oauth_tokens__";
26
+ // deno-lint-ignore no-explicit-any
27
+ const globalStore = globalThis as any;
28
+ const tokens: Map<string, OAuthToken> = globalStore[TOKENS_KEY] ||= new Map<string, OAuthToken>();
25
29
 
26
30
  function getKey(userId: string, service: string): string {
27
31
  return `${userId}:${service}`;
@@ -17,12 +17,8 @@ export default tool({
17
17
  .describe("Maximum number of messages to return"),
18
18
  }),
19
19
  execute: async ({ channel, limit }, context) => {
20
- const userId = context?.userId as string | undefined;
21
- if (!userId) {
22
- return {
23
- error: "User not authenticated. Please log in first.",
24
- };
25
- }
20
+ // Default to "current-user" for development; in production, always pass userId from session
21
+ const userId = (context?.userId as string | undefined) || "current-user";
26
22
 
27
23
  try {
28
24
  const slack = createSlackClient(userId);
@@ -18,12 +18,8 @@ export default tool({
18
18
  .describe("Exclude archived channels"),
19
19
  }),
20
20
  execute: async ({ limit, excludeArchived }, context) => {
21
- const userId = context?.userId as string | undefined;
22
- if (!userId) {
23
- return {
24
- error: "User not authenticated. Please log in first.",
25
- };
26
- }
21
+ // Default to "current-user" for development; in production, always pass userId from session
22
+ const userId = (context?.userId as string | undefined) || "current-user";
27
23
 
28
24
  try {
29
25
  const slack = createSlackClient(userId);
@@ -19,12 +19,8 @@ export default tool({
19
19
  .describe("Thread timestamp to reply to (for threaded messages)"),
20
20
  }),
21
21
  execute: async ({ channel, text, threadTs }, context) => {
22
- const userId = context?.userId as string | undefined;
23
- if (!userId) {
24
- return {
25
- error: "User not authenticated. Please log in first.",
26
- };
27
- }
22
+ // Default to "current-user" for development; in production, always pass userId from session
23
+ const userId = (context?.userId as string | undefined) || "current-user";
28
24
 
29
25
  try {
30
26
  const slack = createSlackClient(userId);
@@ -21,7 +21,11 @@ export interface TokenStore {
21
21
  }
22
22
 
23
23
  // In-memory storage for development
24
- const tokens = new Map<string, OAuthToken>();
24
+ // Use globalThis to share across esbuild bundles (each API route is bundled separately)
25
+ const TOKENS_KEY = "__veryfront_oauth_tokens__";
26
+ // deno-lint-ignore no-explicit-any
27
+ const globalStore = globalThis as any;
28
+ const tokens: Map<string, OAuthToken> = globalStore[TOKENS_KEY] ||= new Map<string, OAuthToken>();
25
29
 
26
30
  function getKey(userId: string, service: string): string {
27
31
  return `${userId}:${service}`;
@@ -20,7 +20,14 @@ export async function POST(request: Request) {
20
20
  return Response.json({ error: "Agent not found" }, { status: 404 });
21
21
  }
22
22
 
23
- const result = await agent.stream({ messages });
23
+ // In production, extract userId from session/cookie
24
+ // For development, we use a default user
25
+ const userId = "current-user";
26
+
27
+ const result = await agent.stream({
28
+ messages,
29
+ context: { userId },
30
+ });
24
31
  return result.toDataStreamResponse();
25
32
  } catch (error) {
26
33
  if (error instanceof z.ZodError) {
@@ -8,10 +8,11 @@ export default function ChatPage() {
8
8
 
9
9
  return (
10
10
  <div className="flex flex-col h-screen bg-white dark:bg-neutral-900">
11
- {/* Header - sticky at top */}
11
+ {/* Header - sticky at top, full width */}
12
12
  <header className="sticky top-0 z-10 flex-shrink-0 border-b border-neutral-200 dark:border-neutral-800 bg-white dark:bg-neutral-900">
13
- <div className="max-w-2xl mx-auto px-4 py-3 flex items-center justify-center">
13
+ <div className="px-4 py-3 flex items-center justify-between">
14
14
  <h1 className="font-medium text-neutral-900 dark:text-white">AI Assistant</h1>
15
+ {/* Add ServiceConnections here when integrations are added */}
15
16
  </div>
16
17
  </header>
17
18
 
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "veryfront",
3
- "version": "0.0.47",
3
+ "version": "0.0.48",
4
4
  "description": "Zero-config React meta-framework for building agentic AI applications",
5
5
  "type": "module",
6
6
  "main": "./dist/index.js",