@chat-js/cli 0.1.1 → 0.1.3
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.
- package/README.md +7 -3
- package/dist/index.js +211 -153
- package/package.json +4 -4
- package/templates/chat-app/app/api/dev-login/route.ts +11 -4
- package/templates/chat-app/app/opengraph-image.png +0 -0
- package/templates/chat-app/biome.jsonc +26 -0
- package/templates/chat-app/chat.config.ts +0 -1
- package/templates/chat-app/components/chat-sync.tsx +2 -4
- package/templates/chat-app/components/followup-suggestions.tsx +22 -14
- package/templates/chat-app/components/header-actions.tsx +0 -12
- package/templates/chat-app/components/image-editor.tsx +1 -1
- package/templates/chat-app/components/part/weather.tsx +1 -1
- package/templates/chat-app/components/social-auth-providers.tsx +2 -0
- package/templates/chat-app/components/toolbar.tsx +1 -1
- package/templates/chat-app/lib/config-schema.ts +0 -1
- package/templates/chat-app/lib/env-schema.ts +118 -0
- package/templates/chat-app/lib/env.ts +2 -49
- package/templates/chat-app/package.json +10 -5
- package/templates/chat-app/scripts/check-env.ts +11 -10
- package/templates/chat-app/.devtools/generations.json +0 -156
- package/templates/chat-app/.gemini/settings.json +0 -3
- package/templates/chat-app/.qwen/settings.json +0 -3
- package/templates/chat-app/next-env.d.ts +0 -6
- package/templates/chat-app/tsconfig.tsbuildinfo +0 -1
package/README.md
CHANGED
|
@@ -5,11 +5,15 @@ CLI to scaffold and extend ChatJS apps.
|
|
|
5
5
|
## Usage
|
|
6
6
|
|
|
7
7
|
```bash
|
|
8
|
-
npx @chat-js/cli@latest
|
|
8
|
+
npx @chat-js/cli@latest
|
|
9
9
|
```
|
|
10
10
|
|
|
11
|
-
|
|
11
|
+
Or with the command alias:
|
|
12
12
|
|
|
13
13
|
```bash
|
|
14
|
-
chat-js create
|
|
14
|
+
npx @chat-js/cli@latest create
|
|
15
15
|
```
|
|
16
|
+
|
|
17
|
+
After install, the binary is:
|
|
18
|
+
|
|
19
|
+
- `chat-js`
|
package/dist/index.js
CHANGED
|
@@ -3914,17 +3914,17 @@ var {
|
|
|
3914
3914
|
// package.json
|
|
3915
3915
|
var package_default = {
|
|
3916
3916
|
name: "@chat-js/cli",
|
|
3917
|
-
version: "0.1.
|
|
3917
|
+
version: "0.1.3",
|
|
3918
3918
|
description: "CLI for creating and extending ChatJS apps",
|
|
3919
3919
|
license: "Apache-2.0",
|
|
3920
3920
|
repository: {
|
|
3921
3921
|
type: "git",
|
|
3922
|
-
url: "https://github.com/
|
|
3922
|
+
url: "https://github.com/franciscomoretti/chat.js.git",
|
|
3923
3923
|
directory: "packages/cli"
|
|
3924
3924
|
},
|
|
3925
|
-
homepage: "https://github.com/
|
|
3925
|
+
homepage: "https://github.com/franciscomoretti/chat.js/tree/main/packages/cli",
|
|
3926
3926
|
bugs: {
|
|
3927
|
-
url: "https://github.com/
|
|
3927
|
+
url: "https://github.com/franciscomoretti/chat.js/issues"
|
|
3928
3928
|
},
|
|
3929
3929
|
keywords: [
|
|
3930
3930
|
"chatjs",
|
|
@@ -18660,105 +18660,6 @@ ${l}
|
|
|
18660
18660
|
}
|
|
18661
18661
|
} }).prompt();
|
|
18662
18662
|
|
|
18663
|
-
// ../../apps/chat/lib/config-requirements.ts
|
|
18664
|
-
var gatewayEnvRequirements = {
|
|
18665
|
-
openrouter: {
|
|
18666
|
-
options: [["OPENROUTER_API_KEY"]],
|
|
18667
|
-
description: "OPENROUTER_API_KEY"
|
|
18668
|
-
},
|
|
18669
|
-
openai: {
|
|
18670
|
-
options: [["OPENAI_API_KEY"]],
|
|
18671
|
-
description: "OPENAI_API_KEY"
|
|
18672
|
-
},
|
|
18673
|
-
vercel: {
|
|
18674
|
-
options: [["AI_GATEWAY_API_KEY"], ["VERCEL_OIDC_TOKEN"]],
|
|
18675
|
-
description: "AI_GATEWAY_API_KEY or VERCEL_OIDC_TOKEN"
|
|
18676
|
-
},
|
|
18677
|
-
"openai-compatible": {
|
|
18678
|
-
options: [["OPENAI_COMPATIBLE_BASE_URL", "OPENAI_COMPATIBLE_API_KEY"]],
|
|
18679
|
-
description: "OPENAI_COMPATIBLE_BASE_URL, OPENAI_COMPATIBLE_API_KEY"
|
|
18680
|
-
}
|
|
18681
|
-
};
|
|
18682
|
-
var featureEnvRequirements = {
|
|
18683
|
-
webSearch: {
|
|
18684
|
-
options: [["TAVILY_API_KEY"], ["FIRECRAWL_API_KEY"]],
|
|
18685
|
-
description: "TAVILY_API_KEY or FIRECRAWL_API_KEY"
|
|
18686
|
-
},
|
|
18687
|
-
deepResearch: {
|
|
18688
|
-
options: [["TAVILY_API_KEY"], ["FIRECRAWL_API_KEY"]],
|
|
18689
|
-
description: "TAVILY_API_KEY or FIRECRAWL_API_KEY"
|
|
18690
|
-
},
|
|
18691
|
-
urlRetrieval: {
|
|
18692
|
-
options: [["FIRECRAWL_API_KEY"]],
|
|
18693
|
-
description: "FIRECRAWL_API_KEY"
|
|
18694
|
-
},
|
|
18695
|
-
mcp: {
|
|
18696
|
-
options: [["MCP_ENCRYPTION_KEY"]],
|
|
18697
|
-
description: "MCP_ENCRYPTION_KEY"
|
|
18698
|
-
},
|
|
18699
|
-
sandbox: {
|
|
18700
|
-
options: [
|
|
18701
|
-
["VERCEL_OIDC_TOKEN"],
|
|
18702
|
-
["VERCEL_TEAM_ID", "VERCEL_PROJECT_ID", "VERCEL_TOKEN"]
|
|
18703
|
-
],
|
|
18704
|
-
description: "VERCEL_OIDC_TOKEN (auto on Vercel) or VERCEL_TEAM_ID + VERCEL_PROJECT_ID + VERCEL_TOKEN"
|
|
18705
|
-
},
|
|
18706
|
-
imageGeneration: {
|
|
18707
|
-
options: [["BLOB_READ_WRITE_TOKEN"]],
|
|
18708
|
-
description: "BLOB_READ_WRITE_TOKEN"
|
|
18709
|
-
},
|
|
18710
|
-
attachments: {
|
|
18711
|
-
options: [["BLOB_READ_WRITE_TOKEN"]],
|
|
18712
|
-
description: "BLOB_READ_WRITE_TOKEN"
|
|
18713
|
-
}
|
|
18714
|
-
};
|
|
18715
|
-
var authEnvRequirements = {
|
|
18716
|
-
google: {
|
|
18717
|
-
options: [["AUTH_GOOGLE_ID", "AUTH_GOOGLE_SECRET"]],
|
|
18718
|
-
description: "AUTH_GOOGLE_ID, AUTH_GOOGLE_SECRET"
|
|
18719
|
-
},
|
|
18720
|
-
github: {
|
|
18721
|
-
options: [["AUTH_GITHUB_ID", "AUTH_GITHUB_SECRET"]],
|
|
18722
|
-
description: "AUTH_GITHUB_ID, AUTH_GITHUB_SECRET"
|
|
18723
|
-
},
|
|
18724
|
-
vercel: {
|
|
18725
|
-
options: [["VERCEL_APP_CLIENT_ID", "VERCEL_APP_CLIENT_SECRET"]],
|
|
18726
|
-
description: "VERCEL_APP_CLIENT_ID, VERCEL_APP_CLIENT_SECRET"
|
|
18727
|
-
}
|
|
18728
|
-
};
|
|
18729
|
-
|
|
18730
|
-
// src/types.ts
|
|
18731
|
-
var FEATURE_KEYS = [
|
|
18732
|
-
"sandbox",
|
|
18733
|
-
"webSearch",
|
|
18734
|
-
"urlRetrieval",
|
|
18735
|
-
"deepResearch",
|
|
18736
|
-
"mcp",
|
|
18737
|
-
"imageGeneration",
|
|
18738
|
-
"attachments",
|
|
18739
|
-
"followupSuggestions"
|
|
18740
|
-
];
|
|
18741
|
-
|
|
18742
|
-
// src/helpers/env-checklist.ts
|
|
18743
|
-
function collectEnvChecklist(input) {
|
|
18744
|
-
const requirements = new Set;
|
|
18745
|
-
requirements.add(gatewayEnvRequirements[input.gateway].description);
|
|
18746
|
-
for (const feature of FEATURE_KEYS) {
|
|
18747
|
-
if (!input.features[feature])
|
|
18748
|
-
continue;
|
|
18749
|
-
const requirement = featureEnvRequirements[feature];
|
|
18750
|
-
if (requirement) {
|
|
18751
|
-
requirements.add(requirement.description);
|
|
18752
|
-
}
|
|
18753
|
-
}
|
|
18754
|
-
for (const provider of Object.keys(authEnvRequirements)) {
|
|
18755
|
-
if (!input.auth[provider])
|
|
18756
|
-
continue;
|
|
18757
|
-
requirements.add(authEnvRequirements[provider].description);
|
|
18758
|
-
}
|
|
18759
|
-
return [...requirements].sort();
|
|
18760
|
-
}
|
|
18761
|
-
|
|
18762
18663
|
// ../../apps/chat/lib/ai/gateway-model-defaults.ts
|
|
18763
18664
|
var multiProviderDefaults = {
|
|
18764
18665
|
providerOrder: ["openai", "google", "anthropic"],
|
|
@@ -18994,7 +18895,6 @@ var authenticationConfigSchema = exports_external.object({
|
|
|
18994
18895
|
vercel: false
|
|
18995
18896
|
});
|
|
18996
18897
|
var configSchema = exports_external.object({
|
|
18997
|
-
githubUrl: exports_external.url().default("https://github.com/your-username/your-repo"),
|
|
18998
18898
|
appPrefix: exports_external.string().default("chatjs"),
|
|
18999
18899
|
appName: exports_external.string().default("My AI Chat"),
|
|
19000
18900
|
appTitle: exports_external.string().optional().describe("Browser tab title (defaults to appName)"),
|
|
@@ -19124,7 +19024,6 @@ ${spaces}},`;
|
|
|
19124
19024
|
function buildConfigTs(input) {
|
|
19125
19025
|
const modelDefaults = GATEWAY_MODEL_DEFAULTS[input.gateway];
|
|
19126
19026
|
const fullConfig = {
|
|
19127
|
-
githubUrl: input.githubUrl,
|
|
19128
19027
|
appPrefix: input.appPrefix,
|
|
19129
19028
|
appName: input.appName,
|
|
19130
19029
|
appDescription: "AI chat powered by ChatJS",
|
|
@@ -19211,6 +19110,179 @@ async function ensureTargetEmpty(targetDir) {
|
|
|
19211
19110
|
}
|
|
19212
19111
|
}
|
|
19213
19112
|
|
|
19113
|
+
// ../../apps/chat/lib/config-requirements.ts
|
|
19114
|
+
var gatewayEnvRequirements = {
|
|
19115
|
+
openrouter: {
|
|
19116
|
+
options: [["OPENROUTER_API_KEY"]],
|
|
19117
|
+
description: "OPENROUTER_API_KEY"
|
|
19118
|
+
},
|
|
19119
|
+
openai: {
|
|
19120
|
+
options: [["OPENAI_API_KEY"]],
|
|
19121
|
+
description: "OPENAI_API_KEY"
|
|
19122
|
+
},
|
|
19123
|
+
vercel: {
|
|
19124
|
+
options: [["AI_GATEWAY_API_KEY"], ["VERCEL_OIDC_TOKEN"]],
|
|
19125
|
+
description: "AI_GATEWAY_API_KEY or VERCEL_OIDC_TOKEN"
|
|
19126
|
+
},
|
|
19127
|
+
"openai-compatible": {
|
|
19128
|
+
options: [["OPENAI_COMPATIBLE_BASE_URL", "OPENAI_COMPATIBLE_API_KEY"]],
|
|
19129
|
+
description: "OPENAI_COMPATIBLE_BASE_URL, OPENAI_COMPATIBLE_API_KEY"
|
|
19130
|
+
}
|
|
19131
|
+
};
|
|
19132
|
+
var featureEnvRequirements = {
|
|
19133
|
+
webSearch: {
|
|
19134
|
+
options: [["TAVILY_API_KEY"], ["FIRECRAWL_API_KEY"]],
|
|
19135
|
+
description: "TAVILY_API_KEY or FIRECRAWL_API_KEY"
|
|
19136
|
+
},
|
|
19137
|
+
deepResearch: {
|
|
19138
|
+
options: [["TAVILY_API_KEY"], ["FIRECRAWL_API_KEY"]],
|
|
19139
|
+
description: "TAVILY_API_KEY or FIRECRAWL_API_KEY"
|
|
19140
|
+
},
|
|
19141
|
+
urlRetrieval: {
|
|
19142
|
+
options: [["FIRECRAWL_API_KEY"]],
|
|
19143
|
+
description: "FIRECRAWL_API_KEY"
|
|
19144
|
+
},
|
|
19145
|
+
mcp: {
|
|
19146
|
+
options: [["MCP_ENCRYPTION_KEY"]],
|
|
19147
|
+
description: "MCP_ENCRYPTION_KEY"
|
|
19148
|
+
},
|
|
19149
|
+
sandbox: {
|
|
19150
|
+
options: [
|
|
19151
|
+
["VERCEL_OIDC_TOKEN"],
|
|
19152
|
+
["VERCEL_TEAM_ID", "VERCEL_PROJECT_ID", "VERCEL_TOKEN"]
|
|
19153
|
+
],
|
|
19154
|
+
description: "VERCEL_OIDC_TOKEN (auto on Vercel) or VERCEL_TEAM_ID + VERCEL_PROJECT_ID + VERCEL_TOKEN"
|
|
19155
|
+
},
|
|
19156
|
+
imageGeneration: {
|
|
19157
|
+
options: [["BLOB_READ_WRITE_TOKEN"]],
|
|
19158
|
+
description: "BLOB_READ_WRITE_TOKEN"
|
|
19159
|
+
},
|
|
19160
|
+
attachments: {
|
|
19161
|
+
options: [["BLOB_READ_WRITE_TOKEN"]],
|
|
19162
|
+
description: "BLOB_READ_WRITE_TOKEN"
|
|
19163
|
+
}
|
|
19164
|
+
};
|
|
19165
|
+
var authEnvRequirements = {
|
|
19166
|
+
google: {
|
|
19167
|
+
options: [["AUTH_GOOGLE_ID", "AUTH_GOOGLE_SECRET"]],
|
|
19168
|
+
description: "AUTH_GOOGLE_ID, AUTH_GOOGLE_SECRET"
|
|
19169
|
+
},
|
|
19170
|
+
github: {
|
|
19171
|
+
options: [["AUTH_GITHUB_ID", "AUTH_GITHUB_SECRET"]],
|
|
19172
|
+
description: "AUTH_GITHUB_ID, AUTH_GITHUB_SECRET"
|
|
19173
|
+
},
|
|
19174
|
+
vercel: {
|
|
19175
|
+
options: [["VERCEL_APP_CLIENT_ID", "VERCEL_APP_CLIENT_SECRET"]],
|
|
19176
|
+
description: "VERCEL_APP_CLIENT_ID, VERCEL_APP_CLIENT_SECRET"
|
|
19177
|
+
}
|
|
19178
|
+
};
|
|
19179
|
+
|
|
19180
|
+
// ../../apps/chat/lib/env-schema.ts
|
|
19181
|
+
var serverEnvSchema = {
|
|
19182
|
+
DATABASE_URL: exports_external.string().min(1).describe("Postgres connection string"),
|
|
19183
|
+
AUTH_SECRET: exports_external.string().min(1).describe("NextAuth.js secret for signing session tokens"),
|
|
19184
|
+
BLOB_READ_WRITE_TOKEN: exports_external.string().optional().describe("Vercel Blob storage token for file uploads"),
|
|
19185
|
+
AUTH_GOOGLE_ID: exports_external.string().optional().describe("Google OAuth client ID"),
|
|
19186
|
+
AUTH_GOOGLE_SECRET: exports_external.string().optional().describe("Google OAuth client secret"),
|
|
19187
|
+
AUTH_GITHUB_ID: exports_external.string().optional().describe("GitHub OAuth app client ID"),
|
|
19188
|
+
AUTH_GITHUB_SECRET: exports_external.string().optional().describe("GitHub OAuth app client secret"),
|
|
19189
|
+
VERCEL_APP_CLIENT_ID: exports_external.string().optional().describe("Vercel OAuth integration client ID"),
|
|
19190
|
+
VERCEL_APP_CLIENT_SECRET: exports_external.string().optional().describe("Vercel OAuth integration client secret"),
|
|
19191
|
+
AI_GATEWAY_API_KEY: exports_external.string().optional().describe("Vercel AI Gateway API key"),
|
|
19192
|
+
VERCEL_OIDC_TOKEN: exports_external.string().optional().describe("Vercel OIDC token (auto-set on Vercel deployments)"),
|
|
19193
|
+
OPENROUTER_API_KEY: exports_external.string().optional().describe("OpenRouter API key"),
|
|
19194
|
+
OPENAI_COMPATIBLE_BASE_URL: exports_external.string().url().optional().describe("Base URL for OpenAI-compatible provider"),
|
|
19195
|
+
OPENAI_COMPATIBLE_API_KEY: exports_external.string().optional().describe("API key for OpenAI-compatible provider"),
|
|
19196
|
+
OPENAI_API_KEY: exports_external.string().optional().describe("OpenAI API key"),
|
|
19197
|
+
CRON_SECRET: exports_external.string().optional().describe("Secret for cleanup cron job endpoint"),
|
|
19198
|
+
REDIS_URL: exports_external.string().optional().describe("Redis URL for resumable streams"),
|
|
19199
|
+
TAVILY_API_KEY: exports_external.string().optional().describe("Tavily API key for web search"),
|
|
19200
|
+
EXA_API_KEY: exports_external.string().optional().describe("Exa API key for web search"),
|
|
19201
|
+
FIRECRAWL_API_KEY: exports_external.string().optional().describe("Firecrawl API key for web search and URL retrieval"),
|
|
19202
|
+
MCP_ENCRYPTION_KEY: exports_external.union([exports_external.string().length(44), exports_external.literal("")]).optional().describe("Encryption key for MCP server credentials (base64, 44 chars)"),
|
|
19203
|
+
VERCEL_TEAM_ID: exports_external.string().optional().describe("Vercel team ID for sandbox (non-Vercel deployments)"),
|
|
19204
|
+
VERCEL_PROJECT_ID: exports_external.string().optional().describe("Vercel project ID for sandbox (non-Vercel deployments)"),
|
|
19205
|
+
VERCEL_TOKEN: exports_external.string().optional().describe("Vercel API token for sandbox (non-Vercel deployments)"),
|
|
19206
|
+
VERCEL_SANDBOX_RUNTIME: exports_external.string().optional().describe("Vercel sandbox runtime identifier"),
|
|
19207
|
+
APP_URL: exports_external.url().optional().describe("App URL for non-Vercel deployments (full URL including https://)"),
|
|
19208
|
+
VERCEL_URL: exports_external.string().optional().describe("Auto-set by Vercel platform")
|
|
19209
|
+
};
|
|
19210
|
+
|
|
19211
|
+
// src/types.ts
|
|
19212
|
+
var FEATURE_KEYS = [
|
|
19213
|
+
"sandbox",
|
|
19214
|
+
"webSearch",
|
|
19215
|
+
"urlRetrieval",
|
|
19216
|
+
"deepResearch",
|
|
19217
|
+
"mcp",
|
|
19218
|
+
"imageGeneration",
|
|
19219
|
+
"attachments",
|
|
19220
|
+
"followupSuggestions"
|
|
19221
|
+
];
|
|
19222
|
+
|
|
19223
|
+
// src/helpers/env-checklist.ts
|
|
19224
|
+
function extractEnvDescriptions() {
|
|
19225
|
+
const result = new Map;
|
|
19226
|
+
for (const [key, schema] of Object.entries(serverEnvSchema)) {
|
|
19227
|
+
const desc = schema.description;
|
|
19228
|
+
if (desc) {
|
|
19229
|
+
result.set(key, desc);
|
|
19230
|
+
}
|
|
19231
|
+
}
|
|
19232
|
+
return result;
|
|
19233
|
+
}
|
|
19234
|
+
var envDescriptions = extractEnvDescriptions();
|
|
19235
|
+
function requirementToEntries(requirement) {
|
|
19236
|
+
const oneOfGroup = requirement.options.length > 1 ? requirement.options.map((group) => group.map(String).join("+")).join("|") : undefined;
|
|
19237
|
+
return requirement.options.map((group) => {
|
|
19238
|
+
const description = group.map((v) => {
|
|
19239
|
+
const varName = String(v);
|
|
19240
|
+
return envDescriptions.get(varName) ?? varName;
|
|
19241
|
+
}).join(", ");
|
|
19242
|
+
return {
|
|
19243
|
+
vars: group.map(String).join(" + "),
|
|
19244
|
+
description: description || requirement.description,
|
|
19245
|
+
oneOfGroup
|
|
19246
|
+
};
|
|
19247
|
+
});
|
|
19248
|
+
}
|
|
19249
|
+
function collectEnvChecklist(input) {
|
|
19250
|
+
const entries = [];
|
|
19251
|
+
entries.push({
|
|
19252
|
+
vars: "AUTH_SECRET",
|
|
19253
|
+
description: envDescriptions.get("AUTH_SECRET") ?? "AUTH_SECRET"
|
|
19254
|
+
});
|
|
19255
|
+
entries.push({
|
|
19256
|
+
vars: "DATABASE_URL",
|
|
19257
|
+
description: envDescriptions.get("DATABASE_URL") ?? "DATABASE_URL"
|
|
19258
|
+
});
|
|
19259
|
+
const gwReq = gatewayEnvRequirements[input.gateway];
|
|
19260
|
+
const gwEntries = requirementToEntries(gwReq);
|
|
19261
|
+
entries.push(...gwEntries);
|
|
19262
|
+
const featureItems = [];
|
|
19263
|
+
const seen = new Set;
|
|
19264
|
+
for (const feature of FEATURE_KEYS) {
|
|
19265
|
+
if (!input.features[feature])
|
|
19266
|
+
continue;
|
|
19267
|
+
const requirement = featureEnvRequirements[feature];
|
|
19268
|
+
if (!requirement)
|
|
19269
|
+
continue;
|
|
19270
|
+
if (seen.has(requirement.description))
|
|
19271
|
+
continue;
|
|
19272
|
+
seen.add(requirement.description);
|
|
19273
|
+
featureItems.push(...requirementToEntries(requirement));
|
|
19274
|
+
}
|
|
19275
|
+
entries.push(...featureItems);
|
|
19276
|
+
const authItems = [];
|
|
19277
|
+
for (const provider of Object.keys(authEnvRequirements)) {
|
|
19278
|
+
if (!input.auth[provider])
|
|
19279
|
+
continue;
|
|
19280
|
+
authItems.push(...requirementToEntries(authEnvRequirements[provider]));
|
|
19281
|
+
}
|
|
19282
|
+
entries.push(...authItems);
|
|
19283
|
+
return entries;
|
|
19284
|
+
}
|
|
19285
|
+
|
|
19214
19286
|
// src/helpers/prompts.ts
|
|
19215
19287
|
var FEATURE_DEFAULTS = {
|
|
19216
19288
|
sandbox: false,
|
|
@@ -19266,42 +19338,6 @@ async function promptProjectName(targetArg, skipPrompt) {
|
|
|
19266
19338
|
handleCancel(name);
|
|
19267
19339
|
return toKebabCase(name) || "my-chat-app";
|
|
19268
19340
|
}
|
|
19269
|
-
async function promptAppDetails(skipPrompt) {
|
|
19270
|
-
if (skipPrompt) {
|
|
19271
|
-
return {
|
|
19272
|
-
appName: "My Chat App",
|
|
19273
|
-
appPrefix: "chat",
|
|
19274
|
-
appUrl: "http://localhost:3000",
|
|
19275
|
-
githubUrl: "https://github.com/your-org/your-repo"
|
|
19276
|
-
};
|
|
19277
|
-
}
|
|
19278
|
-
const appName = await Ze({
|
|
19279
|
-
message: `What is the ${highlighter.info("display name")} of your app?`,
|
|
19280
|
-
initialValue: "My Chat App"
|
|
19281
|
-
});
|
|
19282
|
-
handleCancel(appName);
|
|
19283
|
-
const appPrefix = await Ze({
|
|
19284
|
-
message: `What ${highlighter.info("prefix")} should be used?`,
|
|
19285
|
-
initialValue: toKebabCase(appName) || "chat"
|
|
19286
|
-
});
|
|
19287
|
-
handleCancel(appPrefix);
|
|
19288
|
-
const appUrl = await Ze({
|
|
19289
|
-
message: `What is your ${highlighter.info("app URL")}?`,
|
|
19290
|
-
initialValue: "http://localhost:3000"
|
|
19291
|
-
});
|
|
19292
|
-
handleCancel(appUrl);
|
|
19293
|
-
const githubUrl = await Ze({
|
|
19294
|
-
message: `What is your ${highlighter.info("GitHub repository URL")}?`,
|
|
19295
|
-
initialValue: "https://github.com/your-org/your-repo"
|
|
19296
|
-
});
|
|
19297
|
-
handleCancel(githubUrl);
|
|
19298
|
-
return {
|
|
19299
|
-
appName: appName || "My Chat App",
|
|
19300
|
-
appPrefix: appPrefix || "chat",
|
|
19301
|
-
appUrl: appUrl || "http://localhost:3000",
|
|
19302
|
-
githubUrl: githubUrl || "https://github.com/your-org/your-repo"
|
|
19303
|
-
};
|
|
19304
|
-
}
|
|
19305
19341
|
async function promptGateway(skipPrompt) {
|
|
19306
19342
|
if (skipPrompt)
|
|
19307
19343
|
return "vercel";
|
|
@@ -20751,6 +20787,24 @@ function spinner(text, options) {
|
|
|
20751
20787
|
}
|
|
20752
20788
|
|
|
20753
20789
|
// src/commands/create.ts
|
|
20790
|
+
function printEnvChecklist(entries) {
|
|
20791
|
+
logger.info("Required for your configuration:");
|
|
20792
|
+
logger.break();
|
|
20793
|
+
for (let i = 0;i < entries.length; i += 1) {
|
|
20794
|
+
const entry = entries[i];
|
|
20795
|
+
if (!entry.oneOfGroup) {
|
|
20796
|
+
logger.log(` ${highlighter.warn("*")} ${highlighter.warn(entry.vars)} ${highlighter.dim(`- ${entry.description}`)}`);
|
|
20797
|
+
continue;
|
|
20798
|
+
}
|
|
20799
|
+
logger.log(` ${highlighter.warn("*")} ${highlighter.dim("One of:")}`);
|
|
20800
|
+
while (i < entries.length && entries[i].oneOfGroup === entry.oneOfGroup) {
|
|
20801
|
+
const option = entries[i];
|
|
20802
|
+
logger.log(` ${highlighter.warn("*")} ${highlighter.warn(option.vars)} ${highlighter.dim(`- ${option.description}`)}`);
|
|
20803
|
+
i += 1;
|
|
20804
|
+
}
|
|
20805
|
+
i -= 1;
|
|
20806
|
+
}
|
|
20807
|
+
}
|
|
20754
20808
|
var createOptionsSchema = exports_external.object({
|
|
20755
20809
|
target: exports_external.string().optional(),
|
|
20756
20810
|
yes: exports_external.boolean(),
|
|
@@ -20769,11 +20823,13 @@ var create = new Command().name("create").description("scaffold a new ChatJS cha
|
|
|
20769
20823
|
}
|
|
20770
20824
|
const projectName = await promptProjectName(options.target, options.yes);
|
|
20771
20825
|
const targetDir = resolve2(process.cwd(), projectName);
|
|
20772
|
-
|
|
20826
|
+
await ensureTargetEmpty(targetDir);
|
|
20827
|
+
const appName = projectName.split("-").map((w) => w.charAt(0).toUpperCase() + w.slice(1)).join(" ");
|
|
20828
|
+
const appPrefix = projectName;
|
|
20829
|
+
const appUrl = "http://localhost:3000";
|
|
20773
20830
|
const gateway = await promptGateway(options.yes);
|
|
20774
20831
|
const features = await promptFeatures(options.yes);
|
|
20775
20832
|
const auth = await promptAuth(options.yes);
|
|
20776
|
-
await ensureTargetEmpty(targetDir);
|
|
20777
20833
|
logger.break();
|
|
20778
20834
|
const scaffoldSpinner = spinner("Scaffolding project...").start();
|
|
20779
20835
|
try {
|
|
@@ -20798,7 +20854,6 @@ var create = new Command().name("create").description("scaffold a new ChatJS cha
|
|
|
20798
20854
|
appName,
|
|
20799
20855
|
appPrefix,
|
|
20800
20856
|
appUrl,
|
|
20801
|
-
githubUrl,
|
|
20802
20857
|
gateway,
|
|
20803
20858
|
features,
|
|
20804
20859
|
auth
|
|
@@ -20820,19 +20875,22 @@ var create = new Command().name("create").description("scaffold a new ChatJS cha
|
|
|
20820
20875
|
throw error48;
|
|
20821
20876
|
}
|
|
20822
20877
|
}
|
|
20823
|
-
const
|
|
20878
|
+
const envEntries = collectEnvChecklist({ gateway, features, auth });
|
|
20824
20879
|
Le("Your ChatJS app is ready!");
|
|
20825
20880
|
logger.info("Next steps:");
|
|
20826
|
-
logger.log(` cd ${highlighter.info(projectName)}`);
|
|
20827
|
-
logger.log(` ${highlighter.info(`${packageManager} run dev`)}`);
|
|
20828
20881
|
logger.break();
|
|
20829
|
-
|
|
20830
|
-
|
|
20831
|
-
|
|
20832
|
-
|
|
20833
|
-
}
|
|
20834
|
-
logger.
|
|
20882
|
+
logger.log(` ${highlighter.dim("1.")} cd ${highlighter.info(projectName)}`);
|
|
20883
|
+
logger.log(` ${highlighter.dim("2.")} Copy ${highlighter.info(".env.example")} to ${highlighter.info(".env.local")} and fill in the values below`);
|
|
20884
|
+
if (!installNow) {
|
|
20885
|
+
logger.log(` ${highlighter.dim("3.")} ${highlighter.info(`${packageManager} install`)}`);
|
|
20886
|
+
logger.log(` ${highlighter.dim("4.")} ${highlighter.info(`${packageManager} run db:push`)}`);
|
|
20887
|
+
logger.log(` ${highlighter.dim("5.")} ${highlighter.info(`${packageManager} run dev`)}`);
|
|
20888
|
+
} else {
|
|
20889
|
+
logger.log(` ${highlighter.dim("3.")} ${highlighter.info(`${packageManager} run db:push`)}`);
|
|
20890
|
+
logger.log(` ${highlighter.dim("4.")} ${highlighter.info(`${packageManager} run dev`)}`);
|
|
20835
20891
|
}
|
|
20892
|
+
logger.break();
|
|
20893
|
+
printEnvChecklist(envEntries);
|
|
20836
20894
|
} catch (error48) {
|
|
20837
20895
|
handleError(error48);
|
|
20838
20896
|
}
|
package/package.json
CHANGED
|
@@ -1,16 +1,16 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@chat-js/cli",
|
|
3
|
-
"version": "0.1.
|
|
3
|
+
"version": "0.1.3",
|
|
4
4
|
"description": "CLI for creating and extending ChatJS apps",
|
|
5
5
|
"license": "Apache-2.0",
|
|
6
6
|
"repository": {
|
|
7
7
|
"type": "git",
|
|
8
|
-
"url": "https://github.com/
|
|
8
|
+
"url": "https://github.com/franciscomoretti/chat.js.git",
|
|
9
9
|
"directory": "packages/cli"
|
|
10
10
|
},
|
|
11
|
-
"homepage": "https://github.com/
|
|
11
|
+
"homepage": "https://github.com/franciscomoretti/chat.js/tree/main/packages/cli",
|
|
12
12
|
"bugs": {
|
|
13
|
-
"url": "https://github.com/
|
|
13
|
+
"url": "https://github.com/franciscomoretti/chat.js/issues"
|
|
14
14
|
},
|
|
15
15
|
"keywords": [
|
|
16
16
|
"chatjs",
|
|
@@ -30,11 +30,18 @@ async function serializeSignedCookie(
|
|
|
30
30
|
const signedValue = encodeURIComponent(`${value}.${base64Sig}`);
|
|
31
31
|
|
|
32
32
|
let cookie = `${name}=${signedValue}`;
|
|
33
|
-
if (opt.path)
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
if (opt.
|
|
33
|
+
if (opt.path) {
|
|
34
|
+
cookie += `; Path=${opt.path}`;
|
|
35
|
+
}
|
|
36
|
+
if (opt.expires) {
|
|
37
|
+
cookie += `; Expires=${opt.expires.toUTCString()}`;
|
|
38
|
+
}
|
|
39
|
+
if (opt.httpOnly) {
|
|
40
|
+
cookie += "; HttpOnly";
|
|
41
|
+
}
|
|
42
|
+
if (opt.sameSite) {
|
|
37
43
|
cookie += `; SameSite=${opt.sameSite.charAt(0).toUpperCase() + opt.sameSite.slice(1)}`;
|
|
44
|
+
}
|
|
38
45
|
return cookie;
|
|
39
46
|
}
|
|
40
47
|
|
|
Binary file
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
{
|
|
2
|
+
"extends": ["ultracite/core", "ultracite/react", "ultracite/next"],
|
|
3
|
+
"files": {
|
|
4
|
+
"includes": [
|
|
5
|
+
"**/*",
|
|
6
|
+
"!.next",
|
|
7
|
+
"!.next",
|
|
8
|
+
"!.devtools",
|
|
9
|
+
"!.devtools",
|
|
10
|
+
"!components/ui",
|
|
11
|
+
"!components/ai-elements",
|
|
12
|
+
"!components/streamdown",
|
|
13
|
+
"!components/stick-to-bottom",
|
|
14
|
+
"!lib/utils.ts",
|
|
15
|
+
"!hooks/use-mobile.ts"
|
|
16
|
+
]
|
|
17
|
+
},
|
|
18
|
+
"linter": {
|
|
19
|
+
"rules": {
|
|
20
|
+
"suspicious": {
|
|
21
|
+
/* Needs more work to fix */
|
|
22
|
+
"noExplicitAny": "off"
|
|
23
|
+
}
|
|
24
|
+
}
|
|
25
|
+
}
|
|
26
|
+
}
|
|
@@ -9,7 +9,6 @@ const isProd = process.env.NODE_ENV === "production";
|
|
|
9
9
|
* @see https://chatjs.dev/docs/reference/config
|
|
10
10
|
*/
|
|
11
11
|
const config = {
|
|
12
|
-
githubUrl: "https://github.com/franciscomoretti/chatjs",
|
|
13
12
|
appPrefix: "chatjs",
|
|
14
13
|
appName: "ChatJS",
|
|
15
14
|
appTitle: "ChatJS - The prod ready AI chat app",
|
|
@@ -35,9 +35,6 @@ export function ChatSync({
|
|
|
35
35
|
|
|
36
36
|
const lastMessage = threadInitialMessages.at(-1);
|
|
37
37
|
const isLastMessagePartial = !!lastMessage?.metadata?.activeStreamId;
|
|
38
|
-
const transportFetch = Object.assign(fetchWithErrorHandlers, {
|
|
39
|
-
preconnect: fetch.preconnect,
|
|
40
|
-
}) satisfies typeof fetch;
|
|
41
38
|
|
|
42
39
|
// Backstop: if we remount ChatSync (e.g. threadEpoch changes), ensure the prior
|
|
43
40
|
// in-flight stream is aborted and we don't replay old deltas.
|
|
@@ -65,7 +62,8 @@ export function ChatSync({
|
|
|
65
62
|
resume: isLastMessagePartial,
|
|
66
63
|
transport: new DefaultChatTransport({
|
|
67
64
|
api: "/api/chat",
|
|
68
|
-
fetch
|
|
65
|
+
// @ts-expect-error CI has a stricter global fetch type (includes preconnect).
|
|
66
|
+
fetch: fetchWithErrorHandlers,
|
|
69
67
|
prepareSendMessagesRequest({ messages, id: requestId, body }) {
|
|
70
68
|
setAutoResume(true);
|
|
71
69
|
|
|
@@ -63,20 +63,28 @@ function FollowUpSuggestions({
|
|
|
63
63
|
<div className={cn("mt-2 mb-2 flex flex-col gap-2", className)}>
|
|
64
64
|
<div className="font-medium text-muted-foreground text-xs">Related</div>
|
|
65
65
|
<Suggestions className="gap-1.5">
|
|
66
|
-
{
|
|
67
|
-
<
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
66
|
+
{(() => {
|
|
67
|
+
const seen = new Map<string, number>();
|
|
68
|
+
return suggestions.map((s) => {
|
|
69
|
+
const count = seen.get(s) ?? 0;
|
|
70
|
+
seen.set(s, count + 1);
|
|
71
|
+
const key = count === 0 ? s : `${s}-${count}`;
|
|
72
|
+
return (
|
|
73
|
+
<Suggestion
|
|
74
|
+
className="h-7 text-muted-foreground hover:text-foreground"
|
|
75
|
+
key={key}
|
|
76
|
+
onClick={handleClick}
|
|
77
|
+
size="sm"
|
|
78
|
+
suggestion={s}
|
|
79
|
+
type="button"
|
|
80
|
+
variant="ghost"
|
|
81
|
+
>
|
|
82
|
+
{s}
|
|
83
|
+
<PlusIcon className="size-3 opacity-70" />
|
|
84
|
+
</Suggestion>
|
|
85
|
+
);
|
|
86
|
+
});
|
|
87
|
+
})()}
|
|
80
88
|
</Suggestions>
|
|
81
89
|
</div>
|
|
82
90
|
);
|
|
@@ -3,14 +3,12 @@
|
|
|
3
3
|
import { LogIn } from "lucide-react";
|
|
4
4
|
import { useRouter } from "next/navigation";
|
|
5
5
|
import { memo } from "react";
|
|
6
|
-
import { GitIcon } from "@/components/icons";
|
|
7
6
|
import { Button } from "@/components/ui/button";
|
|
8
7
|
import {
|
|
9
8
|
Tooltip,
|
|
10
9
|
TooltipContent,
|
|
11
10
|
TooltipTrigger,
|
|
12
11
|
} from "@/components/ui/tooltip";
|
|
13
|
-
import { config } from "@/lib/config";
|
|
14
12
|
import { useSession } from "@/providers/session-provider";
|
|
15
13
|
|
|
16
14
|
function PureHeaderActions() {
|
|
@@ -39,16 +37,6 @@ function PureHeaderActions() {
|
|
|
39
37
|
<TooltipContent>Sign in to your account</TooltipContent>
|
|
40
38
|
</Tooltip>
|
|
41
39
|
)}
|
|
42
|
-
<Button asChild size="icon" type="button" variant="ghost">
|
|
43
|
-
<a
|
|
44
|
-
className="flex items-center justify-center"
|
|
45
|
-
href={config.githubUrl}
|
|
46
|
-
rel="noopener noreferrer"
|
|
47
|
-
target="_blank"
|
|
48
|
-
>
|
|
49
|
-
<GitIcon size={20} />
|
|
50
|
-
</a>
|
|
51
|
-
</Button>
|
|
52
40
|
</div>
|
|
53
41
|
);
|
|
54
42
|
}
|
|
@@ -1,10 +1,10 @@
|
|
|
1
1
|
"use client";
|
|
2
2
|
|
|
3
|
-
import { cn } from "@/lib/utils";
|
|
4
3
|
import { format, isWithinInterval } from "date-fns";
|
|
5
4
|
import { useIsMobile } from "@/hooks/use-mobile";
|
|
6
5
|
import type { WeatherAtLocation } from "@/lib/ai/tools/get-weather";
|
|
7
6
|
import type { ChatMessage } from "@/lib/ai/types";
|
|
7
|
+
import { cn } from "@/lib/utils";
|
|
8
8
|
|
|
9
9
|
const SAMPLE = {
|
|
10
10
|
latitude: 37.763_283,
|