create-agents24-app 0.1.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.
- package/LICENSE +21 -0
- package/README.md +11 -0
- package/dist/chunk-OCIF3LSI.js +181 -0
- package/dist/chunk-OCIF3LSI.js.map +1 -0
- package/dist/cli.d.ts +2 -0
- package/dist/cli.js +245 -0
- package/dist/cli.js.map +1 -0
- package/dist/index.d.ts +29 -0
- package/dist/index.js +10 -0
- package/dist/index.js.map +1 -0
- package/package.json +48 -0
- package/templates/common/README.md +24 -0
- package/templates/common/_gitignore +7 -0
- package/templates/common/index.html +14 -0
- package/templates/common/src/styles.css +7 -0
- package/templates/common/src/vite-env.d.ts +1 -0
- package/templates/common/tsconfig.json +21 -0
- package/templates/integrations/bff/server/env.ts +30 -0
- package/templates/integrations/bff/server/index.ts +44 -0
- package/templates/integrations/bff/server/principal.ts +51 -0
- package/templates/integrations/bff/src/main.tsx +26 -0
- package/templates/integrations/bff/tsconfig.json +21 -0
- package/templates/integrations/bff/vite.config.ts +10 -0
- package/templates/integrations/client-deployment/src/main.tsx +31 -0
- package/templates/integrations/client-deployment/vite.config.ts +7 -0
- package/templates/themes/essential/src/theme.css +2 -0
- package/templates/themes/flow/src/theme.css +60 -0
- package/templates/themes/workbench/src/theme.css +51 -0
- package/versions.json +24 -0
package/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 Agents24
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
package/README.md
ADDED
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
# create-agents24-app
|
|
2
|
+
|
|
3
|
+
Last Updated: 2026-07-19
|
|
4
|
+
|
|
5
|
+
Create a canonical Agents24 React/Vite application:
|
|
6
|
+
|
|
7
|
+
```bash
|
|
8
|
+
npm create agents24-app@latest
|
|
9
|
+
```
|
|
10
|
+
|
|
11
|
+
Choose a direct client deployment or a server-backed BFF, then choose the Essential, Workbench, or Flow visual recipe. The generated app contains only the selected integration and recipe.
|
|
@@ -0,0 +1,181 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
|
|
3
|
+
// src/generator.ts
|
|
4
|
+
import { spawnSync } from "child_process";
|
|
5
|
+
import { randomBytes } from "crypto";
|
|
6
|
+
import {
|
|
7
|
+
chmodSync,
|
|
8
|
+
cpSync,
|
|
9
|
+
existsSync,
|
|
10
|
+
mkdirSync,
|
|
11
|
+
readdirSync,
|
|
12
|
+
readFileSync,
|
|
13
|
+
renameSync,
|
|
14
|
+
rmSync,
|
|
15
|
+
statSync,
|
|
16
|
+
writeFileSync
|
|
17
|
+
} from "fs";
|
|
18
|
+
import { basename, dirname, join, resolve } from "path";
|
|
19
|
+
import { fileURLToPath } from "url";
|
|
20
|
+
var packageRoot = resolve(dirname(fileURLToPath(import.meta.url)), "..");
|
|
21
|
+
var templateRoot = join(packageRoot, "templates");
|
|
22
|
+
var versions = JSON.parse(readFileSync(join(packageRoot, "versions.json"), "utf8"));
|
|
23
|
+
function packageName(directory) {
|
|
24
|
+
const value = basename(resolve(directory)).toLowerCase().replace(/[^a-z0-9._-]+/g, "-").replace(/^[._-]+|[._-]+$/g, "");
|
|
25
|
+
if (!value || !/^[a-z0-9]/.test(value)) throw new Error("The destination does not produce a valid npm package name.");
|
|
26
|
+
return value;
|
|
27
|
+
}
|
|
28
|
+
function assertDestination(destination) {
|
|
29
|
+
if (!existsSync(destination)) return;
|
|
30
|
+
if (!statSync(destination).isDirectory()) throw new Error("The destination already exists and is not a directory.");
|
|
31
|
+
if (readdirSync(destination).length > 0) throw new Error("The destination directory must be empty.");
|
|
32
|
+
}
|
|
33
|
+
function walk(directory) {
|
|
34
|
+
return readdirSync(directory, { withFileTypes: true }).flatMap((entry) => {
|
|
35
|
+
const path = join(directory, entry.name);
|
|
36
|
+
return entry.isDirectory() ? walk(path) : [path];
|
|
37
|
+
});
|
|
38
|
+
}
|
|
39
|
+
function replaceTemplateValues(directory, replacements) {
|
|
40
|
+
for (const file of walk(directory)) {
|
|
41
|
+
if (file.endsWith(".png") || file.endsWith(".ico")) continue;
|
|
42
|
+
let content = readFileSync(file, "utf8");
|
|
43
|
+
for (const [token, value] of Object.entries(replacements)) content = content.split(token).join(value);
|
|
44
|
+
writeFileSync(file, content);
|
|
45
|
+
}
|
|
46
|
+
}
|
|
47
|
+
function copyLayer(name, destination) {
|
|
48
|
+
cpSync(join(templateRoot, name), destination, { recursive: true, force: true });
|
|
49
|
+
}
|
|
50
|
+
function generatedManifest(options, name) {
|
|
51
|
+
const dependencies = {
|
|
52
|
+
"@agents24/client": versions.agents24["@agents24/client"],
|
|
53
|
+
"@agents24/react": versions.agents24["@agents24/react"],
|
|
54
|
+
"@agents24/chat-react": versions.agents24["@agents24/chat-react"],
|
|
55
|
+
react: versions.runtime.react,
|
|
56
|
+
"react-dom": versions.runtime["react-dom"]
|
|
57
|
+
};
|
|
58
|
+
const devDependencies = {
|
|
59
|
+
"@types/react": versions.development["@types/react"],
|
|
60
|
+
"@types/react-dom": versions.development["@types/react-dom"],
|
|
61
|
+
"@vitejs/plugin-react": versions.development["@vitejs/plugin-react"],
|
|
62
|
+
typescript: versions.development.typescript,
|
|
63
|
+
vite: versions.development.vite
|
|
64
|
+
};
|
|
65
|
+
const scripts = {
|
|
66
|
+
dev: "vite",
|
|
67
|
+
build: "tsc --noEmit && vite build",
|
|
68
|
+
preview: "vite preview"
|
|
69
|
+
};
|
|
70
|
+
if (options.integration === "bff") {
|
|
71
|
+
dependencies["@agents24/node"] = versions.agents24["@agents24/node"];
|
|
72
|
+
dependencies.hono = versions.runtime.hono;
|
|
73
|
+
dependencies["@hono/node-server"] = versions.runtime["@hono/node-server"];
|
|
74
|
+
devDependencies["@types/node"] = versions.development["@types/node"];
|
|
75
|
+
devDependencies.concurrently = versions.development.concurrently;
|
|
76
|
+
devDependencies.tsx = versions.development.tsx;
|
|
77
|
+
devDependencies.tsup = "^8.5.1";
|
|
78
|
+
scripts.dev = 'concurrently -k -n web,bff "vite" "tsx watch server/index.ts"';
|
|
79
|
+
scripts.build = "tsc --noEmit && vite build && tsup server/index.ts --format esm --platform node --out-dir server-dist --external @agents24/node --external hono --external @hono/node-server";
|
|
80
|
+
scripts.start = "node server-dist/index.js --production";
|
|
81
|
+
}
|
|
82
|
+
return { name, private: true, version: "0.0.0", type: "module", engines: { node: "^22.0.0 || ^24.0.0" }, scripts, dependencies, devDependencies };
|
|
83
|
+
}
|
|
84
|
+
function envFiles(options) {
|
|
85
|
+
const value = (input) => JSON.stringify(String(input || ""));
|
|
86
|
+
if (options.integration === "client-deployment") {
|
|
87
|
+
return {
|
|
88
|
+
example: "VITE_AGENTS24_BASE_URL=https://api.agents24.dev\nVITE_AGENTS24_DEPLOYMENT_ID=acd_your_public_deployment_id\n",
|
|
89
|
+
local: `VITE_AGENTS24_BASE_URL=${value(options.baseUrl)}
|
|
90
|
+
VITE_AGENTS24_DEPLOYMENT_ID=${value(options.deploymentId)}
|
|
91
|
+
`
|
|
92
|
+
};
|
|
93
|
+
}
|
|
94
|
+
return {
|
|
95
|
+
example: [
|
|
96
|
+
"AGENTS24_BASE_URL=https://api.agents24.dev",
|
|
97
|
+
"AGENTS24_API_KEY=your_server_only_api_key",
|
|
98
|
+
"AGENTS24_ORGANIZATION_ID=your_organization_uuid",
|
|
99
|
+
"AGENTS24_PROJECT_ID=your_project_uuid",
|
|
100
|
+
"AGENTS24_AGENT_ID=your_agent_uuid",
|
|
101
|
+
"AGENTS24_AGENT_VERSION_ID=",
|
|
102
|
+
"SESSION_COOKIE_SECRET=generate_at_least_32_random_bytes",
|
|
103
|
+
"PORT=3001",
|
|
104
|
+
""
|
|
105
|
+
].join("\n"),
|
|
106
|
+
local: [
|
|
107
|
+
`AGENTS24_BASE_URL=${value(options.baseUrl)}`,
|
|
108
|
+
`AGENTS24_API_KEY=${value(options.apiKey)}`,
|
|
109
|
+
`AGENTS24_ORGANIZATION_ID=${value(options.organizationId)}`,
|
|
110
|
+
`AGENTS24_PROJECT_ID=${value(options.projectId)}`,
|
|
111
|
+
`AGENTS24_AGENT_ID=${value(options.agentId)}`,
|
|
112
|
+
`AGENTS24_AGENT_VERSION_ID=${value(options.agentVersionId)}`,
|
|
113
|
+
`SESSION_COOKIE_SECRET=${value(randomBytes(32).toString("base64url"))}`,
|
|
114
|
+
"PORT=3001",
|
|
115
|
+
""
|
|
116
|
+
].join("\n")
|
|
117
|
+
};
|
|
118
|
+
}
|
|
119
|
+
function installCommand(packageManager) {
|
|
120
|
+
if (packageManager === "npm") return ["npm", ["install"]];
|
|
121
|
+
if (packageManager === "yarn") return ["yarn", []];
|
|
122
|
+
if (packageManager === "bun") return ["bun", ["install"]];
|
|
123
|
+
return ["pnpm", ["install"]];
|
|
124
|
+
}
|
|
125
|
+
function runScriptCommand(packageManager, script) {
|
|
126
|
+
if (packageManager === "npm") return `npm run ${script}`;
|
|
127
|
+
if (packageManager === "bun") return `bun run ${script}`;
|
|
128
|
+
return `${packageManager} ${script}`;
|
|
129
|
+
}
|
|
130
|
+
function installDependencies(directory, packageManager) {
|
|
131
|
+
const [command, args] = installCommand(packageManager);
|
|
132
|
+
const { AGENTS24_API_KEY: _apiKey, ...installerEnvironment } = process.env;
|
|
133
|
+
const result = spawnSync(command, args, { cwd: directory, stdio: "inherit", env: installerEnvironment });
|
|
134
|
+
if (result.error) throw new Error(`Could not start ${command}: ${result.error.message}`);
|
|
135
|
+
if (result.status !== 0) throw new Error(`${command} ${args.join(" ")} failed with exit ${result.status}.`);
|
|
136
|
+
}
|
|
137
|
+
function createApp(options) {
|
|
138
|
+
const destination = resolve(options.directory);
|
|
139
|
+
assertDestination(destination);
|
|
140
|
+
const name = packageName(destination);
|
|
141
|
+
const parent = dirname(destination);
|
|
142
|
+
mkdirSync(parent, { recursive: true });
|
|
143
|
+
const staging = join(parent, `.${name}.agents24-${randomBytes(6).toString("hex")}`);
|
|
144
|
+
try {
|
|
145
|
+
mkdirSync(staging, { mode: 448 });
|
|
146
|
+
copyLayer("common", staging);
|
|
147
|
+
copyLayer(`integrations/${options.integration}`, staging);
|
|
148
|
+
copyLayer(`themes/${options.theme}`, staging);
|
|
149
|
+
const apiOrigin = new URL(options.baseUrl).origin;
|
|
150
|
+
replaceTemplateValues(staging, {
|
|
151
|
+
"__APP_NAME__": name,
|
|
152
|
+
"__THEME__": options.theme,
|
|
153
|
+
"__INTEGRATION__": options.integration,
|
|
154
|
+
"__CONNECT_SOURCE__": options.integration === "client-deployment" ? apiOrigin : "",
|
|
155
|
+
"__PM_DEV__": runScriptCommand(options.packageManager, "dev"),
|
|
156
|
+
"__PM_BUILD__": runScriptCommand(options.packageManager, "build"),
|
|
157
|
+
"__PM_PRODUCTION__": runScriptCommand(options.packageManager, options.integration === "bff" ? "start" : "preview")
|
|
158
|
+
});
|
|
159
|
+
const gitignore = join(staging, "_gitignore");
|
|
160
|
+
if (existsSync(gitignore)) renameSync(gitignore, join(staging, ".gitignore"));
|
|
161
|
+
writeFileSync(join(staging, "package.json"), `${JSON.stringify(generatedManifest(options, name), null, 2)}
|
|
162
|
+
`);
|
|
163
|
+
const env = envFiles(options);
|
|
164
|
+
writeFileSync(join(staging, ".env.example"), env.example);
|
|
165
|
+
if (options.install) installDependencies(staging, options.packageManager);
|
|
166
|
+
writeFileSync(join(staging, ".env.local"), env.local, { mode: 384 });
|
|
167
|
+
chmodSync(join(staging, ".env.local"), 384);
|
|
168
|
+
if (existsSync(destination)) rmSync(destination, { recursive: true });
|
|
169
|
+
renameSync(staging, destination);
|
|
170
|
+
return { directory: destination, packageName: name };
|
|
171
|
+
} catch (error) {
|
|
172
|
+
rmSync(staging, { recursive: true, force: true });
|
|
173
|
+
throw error;
|
|
174
|
+
}
|
|
175
|
+
}
|
|
176
|
+
|
|
177
|
+
export {
|
|
178
|
+
installDependencies,
|
|
179
|
+
createApp
|
|
180
|
+
};
|
|
181
|
+
//# sourceMappingURL=chunk-OCIF3LSI.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/generator.ts"],"sourcesContent":["import { spawnSync } from \"node:child_process\";\nimport { randomBytes } from \"node:crypto\";\nimport {\n chmodSync,\n cpSync,\n existsSync,\n mkdirSync,\n readdirSync,\n readFileSync,\n renameSync,\n rmSync,\n statSync,\n writeFileSync,\n} from \"node:fs\";\nimport { basename, dirname, join, resolve } from \"node:path\";\nimport { fileURLToPath } from \"node:url\";\n\nimport type { CreateAppOptions, GeneratedApp, PackageManager } from \"./types.js\";\n\ntype Versions = {\n agents24: Record<string, string>;\n runtime: Record<string, string>;\n development: Record<string, string>;\n};\n\nconst packageRoot = resolve(dirname(fileURLToPath(import.meta.url)), \"..\");\nconst templateRoot = join(packageRoot, \"templates\");\nconst versions = JSON.parse(readFileSync(join(packageRoot, \"versions.json\"), \"utf8\")) as Versions;\n\nfunction packageName(directory: string): string {\n const value = basename(resolve(directory))\n .toLowerCase()\n .replace(/[^a-z0-9._-]+/g, \"-\")\n .replace(/^[._-]+|[._-]+$/g, \"\");\n if (!value || !/^[a-z0-9]/.test(value)) throw new Error(\"The destination does not produce a valid npm package name.\");\n return value;\n}\n\nfunction assertDestination(destination: string): void {\n if (!existsSync(destination)) return;\n if (!statSync(destination).isDirectory()) throw new Error(\"The destination already exists and is not a directory.\");\n if (readdirSync(destination).length > 0) throw new Error(\"The destination directory must be empty.\");\n}\n\nfunction walk(directory: string): string[] {\n return readdirSync(directory, { withFileTypes: true }).flatMap((entry) => {\n const path = join(directory, entry.name);\n return entry.isDirectory() ? walk(path) : [path];\n });\n}\n\nfunction replaceTemplateValues(directory: string, replacements: Record<string, string>): void {\n for (const file of walk(directory)) {\n if (file.endsWith(\".png\") || file.endsWith(\".ico\")) continue;\n let content = readFileSync(file, \"utf8\");\n for (const [token, value] of Object.entries(replacements)) content = content.split(token).join(value);\n writeFileSync(file, content);\n }\n}\n\nfunction copyLayer(name: string, destination: string): void {\n cpSync(join(templateRoot, name), destination, { recursive: true, force: true });\n}\n\nfunction generatedManifest(options: CreateAppOptions, name: string): Record<string, unknown> {\n const dependencies: Record<string, string> = {\n \"@agents24/client\": versions.agents24[\"@agents24/client\"]!,\n \"@agents24/react\": versions.agents24[\"@agents24/react\"]!,\n \"@agents24/chat-react\": versions.agents24[\"@agents24/chat-react\"]!,\n react: versions.runtime.react!,\n \"react-dom\": versions.runtime[\"react-dom\"]!,\n };\n const devDependencies: Record<string, string> = {\n \"@types/react\": versions.development[\"@types/react\"]!,\n \"@types/react-dom\": versions.development[\"@types/react-dom\"]!,\n \"@vitejs/plugin-react\": versions.development[\"@vitejs/plugin-react\"]!,\n typescript: versions.development.typescript!,\n vite: versions.development.vite!,\n };\n const scripts: Record<string, string> = {\n dev: \"vite\",\n build: \"tsc --noEmit && vite build\",\n preview: \"vite preview\",\n };\n if (options.integration === \"bff\") {\n dependencies[\"@agents24/node\"] = versions.agents24[\"@agents24/node\"]!;\n dependencies.hono = versions.runtime.hono!;\n dependencies[\"@hono/node-server\"] = versions.runtime[\"@hono/node-server\"]!;\n devDependencies[\"@types/node\"] = versions.development[\"@types/node\"]!;\n devDependencies.concurrently = versions.development.concurrently!;\n devDependencies.tsx = versions.development.tsx!;\n devDependencies.tsup = \"^8.5.1\";\n scripts.dev = \"concurrently -k -n web,bff \\\"vite\\\" \\\"tsx watch server/index.ts\\\"\";\n scripts.build = \"tsc --noEmit && vite build && tsup server/index.ts --format esm --platform node --out-dir server-dist --external @agents24/node --external hono --external @hono/node-server\";\n scripts.start = \"node server-dist/index.js --production\";\n }\n return { name, private: true, version: \"0.0.0\", type: \"module\", engines: { node: \"^22.0.0 || ^24.0.0\" }, scripts, dependencies, devDependencies };\n}\n\nfunction envFiles(options: CreateAppOptions): { example: string; local: string } {\n const value = (input: string | undefined) => JSON.stringify(String(input || \"\"));\n if (options.integration === \"client-deployment\") {\n return {\n example: \"VITE_AGENTS24_BASE_URL=https://api.agents24.dev\\nVITE_AGENTS24_DEPLOYMENT_ID=acd_your_public_deployment_id\\n\",\n local: `VITE_AGENTS24_BASE_URL=${value(options.baseUrl)}\\nVITE_AGENTS24_DEPLOYMENT_ID=${value(options.deploymentId)}\\n`,\n };\n }\n return {\n example: [\n \"AGENTS24_BASE_URL=https://api.agents24.dev\",\n \"AGENTS24_API_KEY=your_server_only_api_key\",\n \"AGENTS24_ORGANIZATION_ID=your_organization_uuid\",\n \"AGENTS24_PROJECT_ID=your_project_uuid\",\n \"AGENTS24_AGENT_ID=your_agent_uuid\",\n \"AGENTS24_AGENT_VERSION_ID=\",\n \"SESSION_COOKIE_SECRET=generate_at_least_32_random_bytes\",\n \"PORT=3001\",\n \"\",\n ].join(\"\\n\"),\n local: [\n `AGENTS24_BASE_URL=${value(options.baseUrl)}`,\n `AGENTS24_API_KEY=${value(options.apiKey)}`,\n `AGENTS24_ORGANIZATION_ID=${value(options.organizationId)}`,\n `AGENTS24_PROJECT_ID=${value(options.projectId)}`,\n `AGENTS24_AGENT_ID=${value(options.agentId)}`,\n `AGENTS24_AGENT_VERSION_ID=${value(options.agentVersionId)}`,\n `SESSION_COOKIE_SECRET=${value(randomBytes(32).toString(\"base64url\"))}`,\n \"PORT=3001\",\n \"\",\n ].join(\"\\n\"),\n };\n}\n\nfunction installCommand(packageManager: PackageManager): [string, string[]] {\n if (packageManager === \"npm\") return [\"npm\", [\"install\"]];\n if (packageManager === \"yarn\") return [\"yarn\", []];\n if (packageManager === \"bun\") return [\"bun\", [\"install\"]];\n return [\"pnpm\", [\"install\"]];\n}\n\nfunction runScriptCommand(packageManager: PackageManager, script: string): string {\n if (packageManager === \"npm\") return `npm run ${script}`;\n if (packageManager === \"bun\") return `bun run ${script}`;\n return `${packageManager} ${script}`;\n}\n\nexport function installDependencies(directory: string, packageManager: PackageManager): void {\n const [command, args] = installCommand(packageManager);\n const { AGENTS24_API_KEY: _apiKey, ...installerEnvironment } = process.env;\n const result = spawnSync(command, args, { cwd: directory, stdio: \"inherit\", env: installerEnvironment });\n if (result.error) throw new Error(`Could not start ${command}: ${result.error.message}`);\n if (result.status !== 0) throw new Error(`${command} ${args.join(\" \")} failed with exit ${result.status}.`);\n}\n\nexport function createApp(options: CreateAppOptions): GeneratedApp {\n const destination = resolve(options.directory);\n assertDestination(destination);\n const name = packageName(destination);\n const parent = dirname(destination);\n mkdirSync(parent, { recursive: true });\n const staging = join(parent, `.${name}.agents24-${randomBytes(6).toString(\"hex\")}`);\n try {\n mkdirSync(staging, { mode: 0o700 });\n copyLayer(\"common\", staging);\n copyLayer(`integrations/${options.integration}`, staging);\n copyLayer(`themes/${options.theme}`, staging);\n const apiOrigin = new URL(options.baseUrl).origin;\n replaceTemplateValues(staging, {\n \"__APP_NAME__\": name,\n \"__THEME__\": options.theme,\n \"__INTEGRATION__\": options.integration,\n \"__CONNECT_SOURCE__\": options.integration === \"client-deployment\" ? apiOrigin : \"\",\n \"__PM_DEV__\": runScriptCommand(options.packageManager, \"dev\"),\n \"__PM_BUILD__\": runScriptCommand(options.packageManager, \"build\"),\n \"__PM_PRODUCTION__\": runScriptCommand(options.packageManager, options.integration === \"bff\" ? \"start\" : \"preview\"),\n });\n const gitignore = join(staging, \"_gitignore\");\n if (existsSync(gitignore)) renameSync(gitignore, join(staging, \".gitignore\"));\n writeFileSync(join(staging, \"package.json\"), `${JSON.stringify(generatedManifest(options, name), null, 2)}\\n`);\n const env = envFiles(options);\n writeFileSync(join(staging, \".env.example\"), env.example);\n if (options.install) installDependencies(staging, options.packageManager);\n writeFileSync(join(staging, \".env.local\"), env.local, { mode: 0o600 });\n chmodSync(join(staging, \".env.local\"), 0o600);\n if (existsSync(destination)) rmSync(destination, { recursive: true });\n renameSync(staging, destination);\n return { directory: destination, packageName: name };\n } catch (error) {\n rmSync(staging, { recursive: true, force: true });\n throw error;\n }\n}\n"],"mappings":"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","names":[]}
|
package/dist/cli.d.ts
ADDED
package/dist/cli.js
ADDED
|
@@ -0,0 +1,245 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
import {
|
|
3
|
+
createApp
|
|
4
|
+
} from "./chunk-OCIF3LSI.js";
|
|
5
|
+
|
|
6
|
+
// src/cli.ts
|
|
7
|
+
import process3 from "process";
|
|
8
|
+
import { intro, outro } from "@clack/prompts";
|
|
9
|
+
|
|
10
|
+
// src/arguments.ts
|
|
11
|
+
import process from "process";
|
|
12
|
+
var VALUE_FLAGS = /* @__PURE__ */ new Set([
|
|
13
|
+
"integration",
|
|
14
|
+
"theme",
|
|
15
|
+
"package-manager",
|
|
16
|
+
"base-url",
|
|
17
|
+
"deployment-id",
|
|
18
|
+
"agent-id",
|
|
19
|
+
"agent-version-id",
|
|
20
|
+
"organization-id",
|
|
21
|
+
"project-id"
|
|
22
|
+
]);
|
|
23
|
+
var BOOLEAN_FLAGS = /* @__PURE__ */ new Set(["yes", "no-install", "help"]);
|
|
24
|
+
function parseArguments(argv = process.argv.slice(2)) {
|
|
25
|
+
const flags = {};
|
|
26
|
+
let directory;
|
|
27
|
+
for (let index = 0; index < argv.length; index += 1) {
|
|
28
|
+
const argument = argv[index] || "";
|
|
29
|
+
if (!argument.startsWith("--")) {
|
|
30
|
+
if (directory) throw new Error("Only one destination directory may be provided.");
|
|
31
|
+
directory = argument;
|
|
32
|
+
continue;
|
|
33
|
+
}
|
|
34
|
+
const [rawName, inlineValue] = argument.slice(2).split("=", 2);
|
|
35
|
+
if (BOOLEAN_FLAGS.has(rawName)) {
|
|
36
|
+
if (inlineValue !== void 0) throw new Error(`--${rawName} does not accept a value.`);
|
|
37
|
+
flags[rawName] = true;
|
|
38
|
+
continue;
|
|
39
|
+
}
|
|
40
|
+
if (!VALUE_FLAGS.has(rawName)) throw new Error(`Unknown option: --${rawName}`);
|
|
41
|
+
const value = inlineValue ?? argv[index + 1];
|
|
42
|
+
if (!value || value.startsWith("--")) throw new Error(`--${rawName} requires a value.`);
|
|
43
|
+
flags[rawName] = value;
|
|
44
|
+
if (inlineValue === void 0) index += 1;
|
|
45
|
+
}
|
|
46
|
+
return { ...directory ? { directory } : {}, flags };
|
|
47
|
+
}
|
|
48
|
+
var HELP = `Create an Agents24 React application.
|
|
49
|
+
|
|
50
|
+
Usage:
|
|
51
|
+
npm create agents24-app@latest [directory] [options]
|
|
52
|
+
|
|
53
|
+
Options:
|
|
54
|
+
--integration <client-deployment|bff>
|
|
55
|
+
--theme <essential|workbench|flow>
|
|
56
|
+
--package-manager <pnpm|npm|yarn|bun>
|
|
57
|
+
--base-url <url>
|
|
58
|
+
--deployment-id <acd_...> Client deployment mode
|
|
59
|
+
--agent-id <uuid> BFF mode
|
|
60
|
+
--agent-version-id <uuid> Optional pinned BFF version
|
|
61
|
+
--organization-id <uuid> BFF mode
|
|
62
|
+
--project-id <uuid> BFF mode
|
|
63
|
+
--no-install
|
|
64
|
+
--yes Disable prompts; required values must be supplied
|
|
65
|
+
--help
|
|
66
|
+
|
|
67
|
+
For security, API keys are accepted only through the masked prompt or the
|
|
68
|
+
AGENTS24_API_KEY environment variable.`;
|
|
69
|
+
|
|
70
|
+
// src/prompts.ts
|
|
71
|
+
import process2 from "process";
|
|
72
|
+
import { confirm, isCancel, password, select, text } from "@clack/prompts";
|
|
73
|
+
|
|
74
|
+
// src/types.ts
|
|
75
|
+
var INTEGRATIONS = ["client-deployment", "bff"];
|
|
76
|
+
var THEMES = ["essential", "workbench", "flow"];
|
|
77
|
+
var PACKAGE_MANAGERS = ["pnpm", "npm", "yarn", "bun"];
|
|
78
|
+
|
|
79
|
+
// src/prompts.ts
|
|
80
|
+
var UUID = /^[0-9a-f]{8}-[0-9a-f]{4}-[1-8][0-9a-f]{3}-[89ab][0-9a-f]{3}-[0-9a-f]{12}$/i;
|
|
81
|
+
var DEPLOYMENT_ID = /^acd_[A-Za-z0-9_-]{10,}$/;
|
|
82
|
+
function cancelled(value) {
|
|
83
|
+
if (isCancel(value)) throw new Error("App creation cancelled.");
|
|
84
|
+
}
|
|
85
|
+
function flag(args, name) {
|
|
86
|
+
const value = args.flags[name];
|
|
87
|
+
return typeof value === "string" ? value.trim() : void 0;
|
|
88
|
+
}
|
|
89
|
+
function oneOf(value, choices, field) {
|
|
90
|
+
if (value === void 0) return void 0;
|
|
91
|
+
if (!choices.includes(value)) throw new Error(`${field} must be one of: ${choices.join(", ")}.`);
|
|
92
|
+
return value;
|
|
93
|
+
}
|
|
94
|
+
function detectedPackageManager() {
|
|
95
|
+
const name = String(process2.env.npm_config_user_agent || "").split("/")[0];
|
|
96
|
+
return PACKAGE_MANAGERS.includes(name) ? name : "pnpm";
|
|
97
|
+
}
|
|
98
|
+
function validateUrl(value) {
|
|
99
|
+
try {
|
|
100
|
+
const parsed = new URL(value);
|
|
101
|
+
if (/[\r\n\0]/.test(value) || parsed.username || parsed.password || parsed.search || parsed.hash) {
|
|
102
|
+
return "Use a base URL without credentials, query parameters, or fragments.";
|
|
103
|
+
}
|
|
104
|
+
return parsed.protocol === "https:" || parsed.protocol === "http:" && ["localhost", "127.0.0.1", "::1"].includes(parsed.hostname) ? void 0 : "Use HTTPS, or HTTP for a local development server.";
|
|
105
|
+
} catch {
|
|
106
|
+
return "Enter a valid URL.";
|
|
107
|
+
}
|
|
108
|
+
}
|
|
109
|
+
async function requiredText(message, initialValue, validate) {
|
|
110
|
+
const result = await text({
|
|
111
|
+
message,
|
|
112
|
+
...initialValue ? { initialValue } : {},
|
|
113
|
+
validate(value) {
|
|
114
|
+
const normalized = String(value || "").trim();
|
|
115
|
+
return normalized ? validate?.(normalized) : "This value is required.";
|
|
116
|
+
}
|
|
117
|
+
});
|
|
118
|
+
cancelled(result);
|
|
119
|
+
return String(result).trim();
|
|
120
|
+
}
|
|
121
|
+
async function resolveOptions(args) {
|
|
122
|
+
const nonInteractive = args.flags.yes === true;
|
|
123
|
+
let directory = args.directory;
|
|
124
|
+
let integration = oneOf(flag(args, "integration"), INTEGRATIONS, "integration");
|
|
125
|
+
let theme = oneOf(flag(args, "theme"), THEMES, "theme");
|
|
126
|
+
let packageManager = oneOf(flag(args, "package-manager"), PACKAGE_MANAGERS, "package-manager");
|
|
127
|
+
let baseUrl = flag(args, "base-url");
|
|
128
|
+
let install = args.flags["no-install"] !== true;
|
|
129
|
+
if (!nonInteractive) {
|
|
130
|
+
directory ||= await requiredText("Where should the app be created?", "my-agents24-app");
|
|
131
|
+
if (!integration) {
|
|
132
|
+
const result = await select({ message: "How should the app connect?", options: [
|
|
133
|
+
{ value: "client-deployment", label: "Client deployment", hint: "Direct anonymous browser connection" },
|
|
134
|
+
{ value: "bff", label: "Server BFF", hint: "API key remains on your Node server" }
|
|
135
|
+
] });
|
|
136
|
+
cancelled(result);
|
|
137
|
+
integration = result;
|
|
138
|
+
}
|
|
139
|
+
if (!theme) {
|
|
140
|
+
const result = await select({ message: "Choose a visual recipe", initialValue: "essential", options: [
|
|
141
|
+
{ value: "essential", label: "Essential", hint: "Canonical shared-page UI" },
|
|
142
|
+
{ value: "workbench", label: "Workbench", hint: "Dense and structured" },
|
|
143
|
+
{ value: "flow", label: "Flow", hint: "Soft and conversational" }
|
|
144
|
+
] });
|
|
145
|
+
cancelled(result);
|
|
146
|
+
theme = result;
|
|
147
|
+
}
|
|
148
|
+
if (!packageManager) {
|
|
149
|
+
const detected = detectedPackageManager();
|
|
150
|
+
const result = await select({ message: "Package manager", initialValue: detected, options: PACKAGE_MANAGERS.map((value) => ({ value, label: value })) });
|
|
151
|
+
cancelled(result);
|
|
152
|
+
packageManager = result;
|
|
153
|
+
}
|
|
154
|
+
baseUrl ||= await requiredText("Agents24 API URL", "https://api.agents24.dev", validateUrl);
|
|
155
|
+
if (args.flags["no-install"] !== true) {
|
|
156
|
+
const result = await confirm({ message: "Install dependencies?", initialValue: true });
|
|
157
|
+
cancelled(result);
|
|
158
|
+
install = result;
|
|
159
|
+
}
|
|
160
|
+
}
|
|
161
|
+
directory = String(directory || "").trim();
|
|
162
|
+
integration ||= "client-deployment";
|
|
163
|
+
theme ||= "essential";
|
|
164
|
+
packageManager ||= detectedPackageManager();
|
|
165
|
+
baseUrl ||= "https://api.agents24.dev";
|
|
166
|
+
const urlError = validateUrl(baseUrl);
|
|
167
|
+
if (!directory) throw new Error("A destination directory is required.");
|
|
168
|
+
if (urlError) throw new Error(urlError);
|
|
169
|
+
if (integration === "client-deployment") {
|
|
170
|
+
let deploymentId = flag(args, "deployment-id");
|
|
171
|
+
if (!deploymentId && !nonInteractive) deploymentId = await requiredText("Public deployment ID", void 0, (value) => DEPLOYMENT_ID.test(value) ? void 0 : "Use a public acd_\u2026 deployment ID.");
|
|
172
|
+
if (!deploymentId || !DEPLOYMENT_ID.test(deploymentId)) throw new Error("A valid --deployment-id (acd_\u2026) is required.");
|
|
173
|
+
return { directory, integration, theme, packageManager, install, baseUrl, deploymentId };
|
|
174
|
+
}
|
|
175
|
+
const fields = {
|
|
176
|
+
agentId: flag(args, "agent-id"),
|
|
177
|
+
agentVersionId: flag(args, "agent-version-id"),
|
|
178
|
+
organizationId: flag(args, "organization-id"),
|
|
179
|
+
projectId: flag(args, "project-id")
|
|
180
|
+
};
|
|
181
|
+
if (!nonInteractive) {
|
|
182
|
+
fields.agentId ||= await requiredText("Agent ID", void 0, (value) => UUID.test(value) ? void 0 : "Enter an Agent UUID.");
|
|
183
|
+
fields.organizationId ||= await requiredText("Organization ID", void 0, (value) => UUID.test(value) ? void 0 : "Enter an organization UUID.");
|
|
184
|
+
fields.projectId ||= await requiredText("Project ID", void 0, (value) => UUID.test(value) ? void 0 : "Enter a project UUID.");
|
|
185
|
+
if (!fields.agentVersionId) {
|
|
186
|
+
const result = await text({
|
|
187
|
+
message: "Agent version ID (optional)",
|
|
188
|
+
placeholder: "Leave blank to use latest published",
|
|
189
|
+
validate: (value) => String(value || "").trim() && !UUID.test(String(value).trim()) ? "Enter an Agent version UUID or leave blank." : void 0
|
|
190
|
+
});
|
|
191
|
+
cancelled(result);
|
|
192
|
+
fields.agentVersionId = String(result || "").trim() || void 0;
|
|
193
|
+
}
|
|
194
|
+
}
|
|
195
|
+
for (const [name, value] of Object.entries(fields)) {
|
|
196
|
+
if (name === "agentVersionId" && !value) continue;
|
|
197
|
+
if (!value || !UUID.test(value)) throw new Error(`A valid --${name.replace(/[A-Z]/g, (letter) => `-${letter.toLowerCase()}`)} UUID is required.`);
|
|
198
|
+
}
|
|
199
|
+
let apiKey = String(process2.env.AGENTS24_API_KEY || "").trim();
|
|
200
|
+
if (!apiKey && !nonInteractive) {
|
|
201
|
+
const result = await password({ message: "Agents24 API key", validate: (value) => String(value || "").trim() ? void 0 : "The API key is required." });
|
|
202
|
+
cancelled(result);
|
|
203
|
+
apiKey = String(result).trim();
|
|
204
|
+
}
|
|
205
|
+
if (!apiKey) throw new Error("AGENTS24_API_KEY is required for noninteractive BFF creation.");
|
|
206
|
+
if (/[\r\n\0]/.test(apiKey)) throw new Error("AGENTS24_API_KEY contains invalid control characters.");
|
|
207
|
+
return { directory, integration, theme, packageManager, install, baseUrl, apiKey, ...fields };
|
|
208
|
+
}
|
|
209
|
+
|
|
210
|
+
// src/cli.ts
|
|
211
|
+
function scriptCommand(packageManager, script) {
|
|
212
|
+
if (packageManager === "npm") return `npm run ${script}`;
|
|
213
|
+
if (packageManager === "bun") return `bun run ${script}`;
|
|
214
|
+
return `${packageManager} ${script}`;
|
|
215
|
+
}
|
|
216
|
+
async function main() {
|
|
217
|
+
const args = parseArguments();
|
|
218
|
+
if (args.flags.help) {
|
|
219
|
+
process3.stdout.write(`${HELP}
|
|
220
|
+
`);
|
|
221
|
+
return;
|
|
222
|
+
}
|
|
223
|
+
intro("Create Agents24 App");
|
|
224
|
+
const options = await resolveOptions(args);
|
|
225
|
+
const generated = createApp(options);
|
|
226
|
+
const relative = generated.directory.startsWith(`${process3.cwd()}/`) ? generated.directory.slice(process3.cwd().length + 1) : generated.directory;
|
|
227
|
+
const install = `${options.packageManager} install`;
|
|
228
|
+
const productionScript = options.integration === "bff" ? "start" : "preview";
|
|
229
|
+
outro([
|
|
230
|
+
`Created ${generated.packageName}`,
|
|
231
|
+
"",
|
|
232
|
+
` cd ${relative}`,
|
|
233
|
+
` ${install}${options.install ? " # already completed" : ""}`,
|
|
234
|
+
` ${scriptCommand(options.packageManager, "dev")}`,
|
|
235
|
+
` ${scriptCommand(options.packageManager, "build")}`,
|
|
236
|
+
` ${scriptCommand(options.packageManager, productionScript)}`
|
|
237
|
+
].join("\n"));
|
|
238
|
+
}
|
|
239
|
+
main().catch((error) => {
|
|
240
|
+
const message = error instanceof Error ? error.message : "App creation failed.";
|
|
241
|
+
process3.stderr.write(`create-agents24-app: ${message}
|
|
242
|
+
`);
|
|
243
|
+
process3.exitCode = 1;
|
|
244
|
+
});
|
|
245
|
+
//# sourceMappingURL=cli.js.map
|
package/dist/cli.js.map
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/cli.ts","../src/arguments.ts","../src/prompts.ts","../src/types.ts"],"sourcesContent":["import process from \"node:process\";\nimport { intro, outro } from \"@clack/prompts\";\n\nimport { HELP, parseArguments } from \"./arguments.js\";\nimport { createApp } from \"./generator.js\";\nimport { resolveOptions } from \"./prompts.js\";\n\nfunction scriptCommand(packageManager: string, script: string): string {\n if (packageManager === \"npm\") return `npm run ${script}`;\n if (packageManager === \"bun\") return `bun run ${script}`;\n return `${packageManager} ${script}`;\n}\n\nasync function main(): Promise<void> {\n const args = parseArguments();\n if (args.flags.help) {\n process.stdout.write(`${HELP}\\n`);\n return;\n }\n intro(\"Create Agents24 App\");\n const options = await resolveOptions(args);\n const generated = createApp(options);\n const relative = generated.directory.startsWith(`${process.cwd()}/`)\n ? generated.directory.slice(process.cwd().length + 1)\n : generated.directory;\n const install = `${options.packageManager} install`;\n const productionScript = options.integration === \"bff\" ? \"start\" : \"preview\";\n outro([\n `Created ${generated.packageName}`,\n \"\",\n ` cd ${relative}`,\n ` ${install}${options.install ? \" # already completed\" : \"\"}`,\n ` ${scriptCommand(options.packageManager, \"dev\")}`,\n ` ${scriptCommand(options.packageManager, \"build\")}`,\n ` ${scriptCommand(options.packageManager, productionScript)}`,\n ].join(\"\\n\"));\n}\n\nmain().catch((error: unknown) => {\n const message = error instanceof Error ? error.message : \"App creation failed.\";\n process.stderr.write(`create-agents24-app: ${message}\\n`);\n process.exitCode = 1;\n});\n","import process from \"node:process\";\n\nexport type ParsedArguments = {\n directory?: string;\n flags: Record<string, string | boolean>;\n};\n\nconst VALUE_FLAGS = new Set([\n \"integration\",\n \"theme\",\n \"package-manager\",\n \"base-url\",\n \"deployment-id\",\n \"agent-id\",\n \"agent-version-id\",\n \"organization-id\",\n \"project-id\",\n]);\nconst BOOLEAN_FLAGS = new Set([\"yes\", \"no-install\", \"help\"]);\n\nexport function parseArguments(argv = process.argv.slice(2)): ParsedArguments {\n const flags: Record<string, string | boolean> = {};\n let directory: string | undefined;\n for (let index = 0; index < argv.length; index += 1) {\n const argument = argv[index] || \"\";\n if (!argument.startsWith(\"--\")) {\n if (directory) throw new Error(\"Only one destination directory may be provided.\");\n directory = argument;\n continue;\n }\n const [rawName, inlineValue] = argument.slice(2).split(\"=\", 2);\n if (BOOLEAN_FLAGS.has(rawName)) {\n if (inlineValue !== undefined) throw new Error(`--${rawName} does not accept a value.`);\n flags[rawName] = true;\n continue;\n }\n if (!VALUE_FLAGS.has(rawName)) throw new Error(`Unknown option: --${rawName}`);\n const value = inlineValue ?? argv[index + 1];\n if (!value || value.startsWith(\"--\")) throw new Error(`--${rawName} requires a value.`);\n flags[rawName] = value;\n if (inlineValue === undefined) index += 1;\n }\n return { ...(directory ? { directory } : {}), flags };\n}\n\nexport const HELP = `Create an Agents24 React application.\n\nUsage:\n npm create agents24-app@latest [directory] [options]\n\nOptions:\n --integration <client-deployment|bff>\n --theme <essential|workbench|flow>\n --package-manager <pnpm|npm|yarn|bun>\n --base-url <url>\n --deployment-id <acd_...> Client deployment mode\n --agent-id <uuid> BFF mode\n --agent-version-id <uuid> Optional pinned BFF version\n --organization-id <uuid> BFF mode\n --project-id <uuid> BFF mode\n --no-install\n --yes Disable prompts; required values must be supplied\n --help\n\nFor security, API keys are accepted only through the masked prompt or the\nAGENTS24_API_KEY environment variable.`;\n","import process from \"node:process\";\nimport { confirm, isCancel, password, select, text } from \"@clack/prompts\";\n\nimport type { ParsedArguments } from \"./arguments.js\";\nimport {\n INTEGRATIONS,\n PACKAGE_MANAGERS,\n THEMES,\n type CreateAppOptions,\n type Integration,\n type PackageManager,\n type Theme,\n} from \"./types.js\";\n\nconst UUID = /^[0-9a-f]{8}-[0-9a-f]{4}-[1-8][0-9a-f]{3}-[89ab][0-9a-f]{3}-[0-9a-f]{12}$/i;\nconst DEPLOYMENT_ID = /^acd_[A-Za-z0-9_-]{10,}$/;\n\nfunction cancelled(value: unknown): asserts value is Exclude<typeof value, symbol> {\n if (isCancel(value)) throw new Error(\"App creation cancelled.\");\n}\n\nfunction flag(args: ParsedArguments, name: string): string | undefined {\n const value = args.flags[name];\n return typeof value === \"string\" ? value.trim() : undefined;\n}\n\nfunction oneOf<T extends string>(value: string | undefined, choices: readonly T[], field: string): T | undefined {\n if (value === undefined) return undefined;\n if (!choices.includes(value as T)) throw new Error(`${field} must be one of: ${choices.join(\", \")}.`);\n return value as T;\n}\n\nfunction detectedPackageManager(): PackageManager {\n const name = String(process.env.npm_config_user_agent || \"\").split(\"/\")[0];\n return PACKAGE_MANAGERS.includes(name as PackageManager) ? name as PackageManager : \"pnpm\";\n}\n\nfunction validateUrl(value: string): string | undefined {\n try {\n const parsed = new URL(value);\n if (/[\\r\\n\\0]/.test(value) || parsed.username || parsed.password || parsed.search || parsed.hash) {\n return \"Use a base URL without credentials, query parameters, or fragments.\";\n }\n return parsed.protocol === \"https:\" || (parsed.protocol === \"http:\" && [\"localhost\", \"127.0.0.1\", \"::1\"].includes(parsed.hostname))\n ? undefined\n : \"Use HTTPS, or HTTP for a local development server.\";\n } catch { return \"Enter a valid URL.\"; }\n}\n\nasync function requiredText(message: string, initialValue: string | undefined, validate?: (value: string) => string | undefined): Promise<string> {\n const result = await text({\n message,\n ...(initialValue ? { initialValue } : {}),\n validate(value) {\n const normalized = String(value || \"\").trim();\n return normalized ? validate?.(normalized) : \"This value is required.\";\n },\n });\n cancelled(result);\n return String(result).trim();\n}\n\nexport async function resolveOptions(args: ParsedArguments): Promise<CreateAppOptions> {\n const nonInteractive = args.flags.yes === true;\n let directory = args.directory;\n let integration = oneOf(flag(args, \"integration\"), INTEGRATIONS, \"integration\");\n let theme = oneOf(flag(args, \"theme\"), THEMES, \"theme\");\n let packageManager = oneOf(flag(args, \"package-manager\"), PACKAGE_MANAGERS, \"package-manager\");\n let baseUrl = flag(args, \"base-url\");\n let install = args.flags[\"no-install\"] !== true;\n\n if (!nonInteractive) {\n directory ||= await requiredText(\"Where should the app be created?\", \"my-agents24-app\");\n if (!integration) {\n const result = await select<Integration>({ message: \"How should the app connect?\", options: [\n { value: \"client-deployment\", label: \"Client deployment\", hint: \"Direct anonymous browser connection\" },\n { value: \"bff\", label: \"Server BFF\", hint: \"API key remains on your Node server\" },\n ] });\n cancelled(result); integration = result;\n }\n if (!theme) {\n const result = await select<Theme>({ message: \"Choose a visual recipe\", initialValue: \"essential\", options: [\n { value: \"essential\", label: \"Essential\", hint: \"Canonical shared-page UI\" },\n { value: \"workbench\", label: \"Workbench\", hint: \"Dense and structured\" },\n { value: \"flow\", label: \"Flow\", hint: \"Soft and conversational\" },\n ] });\n cancelled(result); theme = result;\n }\n if (!packageManager) {\n const detected = detectedPackageManager();\n const result = await select<PackageManager>({ message: \"Package manager\", initialValue: detected, options: PACKAGE_MANAGERS.map((value) => ({ value, label: value })) });\n cancelled(result); packageManager = result;\n }\n baseUrl ||= await requiredText(\"Agents24 API URL\", \"https://api.agents24.dev\", validateUrl);\n if (args.flags[\"no-install\"] !== true) {\n const result = await confirm({ message: \"Install dependencies?\", initialValue: true });\n cancelled(result); install = result;\n }\n }\n\n directory = String(directory || \"\").trim();\n integration ||= \"client-deployment\";\n theme ||= \"essential\";\n packageManager ||= detectedPackageManager();\n baseUrl ||= \"https://api.agents24.dev\";\n const urlError = validateUrl(baseUrl);\n if (!directory) throw new Error(\"A destination directory is required.\");\n if (urlError) throw new Error(urlError);\n\n if (integration === \"client-deployment\") {\n let deploymentId = flag(args, \"deployment-id\");\n if (!deploymentId && !nonInteractive) deploymentId = await requiredText(\"Public deployment ID\", undefined, (value) => DEPLOYMENT_ID.test(value) ? undefined : \"Use a public acd_… deployment ID.\");\n if (!deploymentId || !DEPLOYMENT_ID.test(deploymentId)) throw new Error(\"A valid --deployment-id (acd_…) is required.\");\n return { directory, integration, theme, packageManager, install, baseUrl, deploymentId };\n }\n\n const fields = {\n agentId: flag(args, \"agent-id\"),\n agentVersionId: flag(args, \"agent-version-id\"),\n organizationId: flag(args, \"organization-id\"),\n projectId: flag(args, \"project-id\"),\n };\n if (!nonInteractive) {\n fields.agentId ||= await requiredText(\"Agent ID\", undefined, (value) => UUID.test(value) ? undefined : \"Enter an Agent UUID.\");\n fields.organizationId ||= await requiredText(\"Organization ID\", undefined, (value) => UUID.test(value) ? undefined : \"Enter an organization UUID.\");\n fields.projectId ||= await requiredText(\"Project ID\", undefined, (value) => UUID.test(value) ? undefined : \"Enter a project UUID.\");\n if (!fields.agentVersionId) {\n const result = await text({\n message: \"Agent version ID (optional)\",\n placeholder: \"Leave blank to use latest published\",\n validate: (value) => String(value || \"\").trim() && !UUID.test(String(value).trim()) ? \"Enter an Agent version UUID or leave blank.\" : undefined,\n });\n cancelled(result);\n fields.agentVersionId = String(result || \"\").trim() || undefined;\n }\n }\n for (const [name, value] of Object.entries(fields)) {\n if (name === \"agentVersionId\" && !value) continue;\n if (!value || !UUID.test(value)) throw new Error(`A valid --${name.replace(/[A-Z]/g, (letter) => `-${letter.toLowerCase()}`)} UUID is required.`);\n }\n let apiKey = String(process.env.AGENTS24_API_KEY || \"\").trim();\n if (!apiKey && !nonInteractive) {\n const result = await password({ message: \"Agents24 API key\", validate: (value) => String(value || \"\").trim() ? undefined : \"The API key is required.\" });\n cancelled(result); apiKey = String(result).trim();\n }\n if (!apiKey) throw new Error(\"AGENTS24_API_KEY is required for noninteractive BFF creation.\");\n if (/[\\r\\n\\0]/.test(apiKey)) throw new Error(\"AGENTS24_API_KEY contains invalid control characters.\");\n return { directory, integration, theme, packageManager, install, baseUrl, apiKey, ...fields } as CreateAppOptions;\n}\n","export const INTEGRATIONS = [\"client-deployment\", \"bff\"] as const;\nexport const THEMES = [\"essential\", \"workbench\", \"flow\"] as const;\nexport const PACKAGE_MANAGERS = [\"pnpm\", \"npm\", \"yarn\", \"bun\"] as const;\n\nexport type Integration = (typeof INTEGRATIONS)[number];\nexport type Theme = (typeof THEMES)[number];\nexport type PackageManager = (typeof PACKAGE_MANAGERS)[number];\n\nexport type CreateAppOptions = {\n directory: string;\n integration: Integration;\n theme: Theme;\n packageManager: PackageManager;\n install: boolean;\n baseUrl: string;\n deploymentId?: string;\n agentId?: string;\n agentVersionId?: string;\n organizationId?: string;\n projectId?: string;\n apiKey?: string;\n};\n\nexport type GeneratedApp = {\n directory: string;\n packageName: string;\n};\n"],"mappings":"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","names":["process","process","process","process"]}
|
package/dist/index.d.ts
ADDED
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
declare const INTEGRATIONS: readonly ["client-deployment", "bff"];
|
|
2
|
+
declare const THEMES: readonly ["essential", "workbench", "flow"];
|
|
3
|
+
declare const PACKAGE_MANAGERS: readonly ["pnpm", "npm", "yarn", "bun"];
|
|
4
|
+
type Integration = (typeof INTEGRATIONS)[number];
|
|
5
|
+
type Theme = (typeof THEMES)[number];
|
|
6
|
+
type PackageManager = (typeof PACKAGE_MANAGERS)[number];
|
|
7
|
+
type CreateAppOptions = {
|
|
8
|
+
directory: string;
|
|
9
|
+
integration: Integration;
|
|
10
|
+
theme: Theme;
|
|
11
|
+
packageManager: PackageManager;
|
|
12
|
+
install: boolean;
|
|
13
|
+
baseUrl: string;
|
|
14
|
+
deploymentId?: string;
|
|
15
|
+
agentId?: string;
|
|
16
|
+
agentVersionId?: string;
|
|
17
|
+
organizationId?: string;
|
|
18
|
+
projectId?: string;
|
|
19
|
+
apiKey?: string;
|
|
20
|
+
};
|
|
21
|
+
type GeneratedApp = {
|
|
22
|
+
directory: string;
|
|
23
|
+
packageName: string;
|
|
24
|
+
};
|
|
25
|
+
|
|
26
|
+
declare function installDependencies(directory: string, packageManager: PackageManager): void;
|
|
27
|
+
declare function createApp(options: CreateAppOptions): GeneratedApp;
|
|
28
|
+
|
|
29
|
+
export { type CreateAppOptions, type GeneratedApp, type Integration, type PackageManager, type Theme, createApp, installDependencies };
|
package/dist/index.js
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":[],"sourcesContent":[],"mappings":"","names":[]}
|
package/package.json
ADDED
|
@@ -0,0 +1,48 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "create-agents24-app",
|
|
3
|
+
"version": "0.1.0",
|
|
4
|
+
"description": "Create a production-ready Agents24 React application.",
|
|
5
|
+
"license": "MIT",
|
|
6
|
+
"repository": {
|
|
7
|
+
"type": "git",
|
|
8
|
+
"url": "git+https://github.com/daniel5426/talmudpedia.git",
|
|
9
|
+
"directory": "packages/create-agents24-app"
|
|
10
|
+
},
|
|
11
|
+
"type": "module",
|
|
12
|
+
"bin": {
|
|
13
|
+
"create-agents24-app": "./dist/cli.js"
|
|
14
|
+
},
|
|
15
|
+
"exports": {
|
|
16
|
+
".": {
|
|
17
|
+
"types": "./dist/index.d.ts",
|
|
18
|
+
"import": "./dist/index.js"
|
|
19
|
+
}
|
|
20
|
+
},
|
|
21
|
+
"files": [
|
|
22
|
+
"dist",
|
|
23
|
+
"templates",
|
|
24
|
+
"versions.json",
|
|
25
|
+
"README.md",
|
|
26
|
+
"LICENSE"
|
|
27
|
+
],
|
|
28
|
+
"engines": {
|
|
29
|
+
"node": "^22.0.0 || ^24.0.0"
|
|
30
|
+
},
|
|
31
|
+
"publishConfig": {
|
|
32
|
+
"access": "public",
|
|
33
|
+
"provenance": false
|
|
34
|
+
},
|
|
35
|
+
"dependencies": {
|
|
36
|
+
"@clack/prompts": "1.7.0"
|
|
37
|
+
},
|
|
38
|
+
"devDependencies": {
|
|
39
|
+
"@types/node": "^24.7.2",
|
|
40
|
+
"tsup": "^8.5.1",
|
|
41
|
+
"typescript": "^5.9.3"
|
|
42
|
+
},
|
|
43
|
+
"scripts": {
|
|
44
|
+
"build": "tsup",
|
|
45
|
+
"test": "pnpm run build && node --test tests/*.test.mjs",
|
|
46
|
+
"prepack": "pnpm run build && pnpm run test"
|
|
47
|
+
}
|
|
48
|
+
}
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
# __APP_NAME__
|
|
2
|
+
|
|
3
|
+
Last Updated: 2026-07-19
|
|
4
|
+
|
|
5
|
+
This app was generated by `create-agents24-app` with the `__INTEGRATION__` integration and `__THEME__` visual recipe.
|
|
6
|
+
|
|
7
|
+
The app includes a strict document CSP. If you deploy the static client-deployment build without the generated BFF, configure your host to send `Content-Security-Policy: frame-ancestors 'none'`; browsers do not honor that directive in an HTML meta tag.
|
|
8
|
+
|
|
9
|
+
## Development
|
|
10
|
+
|
|
11
|
+
```bash
|
|
12
|
+
__PM_DEV__
|
|
13
|
+
```
|
|
14
|
+
|
|
15
|
+
Configuration lives in `.env.local`. Commit `.env.example`, never `.env.local`.
|
|
16
|
+
|
|
17
|
+
## Production
|
|
18
|
+
|
|
19
|
+
```bash
|
|
20
|
+
__PM_BUILD__
|
|
21
|
+
__PM_PRODUCTION__
|
|
22
|
+
```
|
|
23
|
+
|
|
24
|
+
The chat layout comes directly from `@agents24/chat-react`; keep product-specific additions in the provided slots instead of copying the layout.
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
<!doctype html>
|
|
2
|
+
<html lang="en" data-agents24-color-mode="system">
|
|
3
|
+
<head>
|
|
4
|
+
<meta charset="UTF-8" />
|
|
5
|
+
<meta content="width=device-width, initial-scale=1.0" name="viewport" />
|
|
6
|
+
<meta content="default-src 'self'; base-uri 'none'; object-src 'none'; script-src 'self'; style-src 'self'; img-src 'self' data: blob:; connect-src 'self' __CONNECT_SOURCE__ ws://127.0.0.1:* ws://localhost:*; form-action 'self'" http-equiv="Content-Security-Policy" />
|
|
7
|
+
<link href="/src/styles.css" rel="stylesheet" />
|
|
8
|
+
<title>__APP_NAME__</title>
|
|
9
|
+
</head>
|
|
10
|
+
<body>
|
|
11
|
+
<div id="root"></div>
|
|
12
|
+
<script src="/src/main.tsx" type="module"></script>
|
|
13
|
+
</body>
|
|
14
|
+
</html>
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
@import "@agents24/chat-react/styles.css";
|
|
2
|
+
@import "./theme.css";
|
|
3
|
+
|
|
4
|
+
* { box-sizing: border-box; }
|
|
5
|
+
html, body, #root { height: 100%; margin: 0; }
|
|
6
|
+
body { background: var(--a24-background); color: var(--a24-text); overflow: hidden; }
|
|
7
|
+
.app-shell { height: 100%; min-height: 32rem; width: 100%; }
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
/// <reference types="vite/client" />
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
{
|
|
2
|
+
"compilerOptions": {
|
|
3
|
+
"target": "ES2022",
|
|
4
|
+
"useDefineForClassFields": true,
|
|
5
|
+
"lib": ["ES2022", "DOM", "DOM.Iterable"],
|
|
6
|
+
"allowJs": false,
|
|
7
|
+
"skipLibCheck": true,
|
|
8
|
+
"esModuleInterop": true,
|
|
9
|
+
"allowSyntheticDefaultImports": true,
|
|
10
|
+
"strict": true,
|
|
11
|
+
"forceConsistentCasingInFileNames": true,
|
|
12
|
+
"module": "ESNext",
|
|
13
|
+
"moduleResolution": "Bundler",
|
|
14
|
+
"resolveJsonModule": true,
|
|
15
|
+
"isolatedModules": true,
|
|
16
|
+
"noEmit": true,
|
|
17
|
+
"jsx": "react-jsx",
|
|
18
|
+
"types": ["vite/client"]
|
|
19
|
+
},
|
|
20
|
+
"include": ["src", "server", "vite.config.ts"]
|
|
21
|
+
}
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
import process from "node:process";
|
|
2
|
+
|
|
3
|
+
try { process.loadEnvFile?.(".env.local"); }
|
|
4
|
+
catch (error) {
|
|
5
|
+
if ((error as NodeJS.ErrnoException).code !== "ENOENT") throw error;
|
|
6
|
+
}
|
|
7
|
+
|
|
8
|
+
const REQUIRED = [
|
|
9
|
+
"AGENTS24_BASE_URL",
|
|
10
|
+
"AGENTS24_API_KEY",
|
|
11
|
+
"AGENTS24_ORGANIZATION_ID",
|
|
12
|
+
"AGENTS24_PROJECT_ID",
|
|
13
|
+
"AGENTS24_AGENT_ID",
|
|
14
|
+
"SESSION_COOKIE_SECRET",
|
|
15
|
+
] as const;
|
|
16
|
+
|
|
17
|
+
function required(name: (typeof REQUIRED)[number]): string {
|
|
18
|
+
const value = String(process.env[name] || "").trim();
|
|
19
|
+
if (!value) throw new Error(`${name} is required.`);
|
|
20
|
+
return value;
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
export const env = {
|
|
24
|
+
...Object.fromEntries(REQUIRED.map((name) => [name, required(name)])) as Record<(typeof REQUIRED)[number], string>,
|
|
25
|
+
AGENTS24_AGENT_VERSION_ID: String(process.env.AGENTS24_AGENT_VERSION_ID || "").trim() || undefined,
|
|
26
|
+
PORT: Number(process.env.PORT || 3001),
|
|
27
|
+
};
|
|
28
|
+
|
|
29
|
+
if (!Number.isInteger(env.PORT) || env.PORT < 1 || env.PORT > 65535) throw new Error("PORT must be a valid port.");
|
|
30
|
+
if (env.SESSION_COOKIE_SECRET.length < 32) throw new Error("SESSION_COOKIE_SECRET must contain at least 32 characters.");
|
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
import { readFile } from "node:fs/promises";
|
|
2
|
+
import { resolve } from "node:path";
|
|
3
|
+
import { serve } from "@hono/node-server";
|
|
4
|
+
import { serveStatic } from "@hono/node-server/serve-static";
|
|
5
|
+
import { Agents24 } from "@agents24/node";
|
|
6
|
+
import { createAgents24BffHandler } from "@agents24/node/bff";
|
|
7
|
+
import { Hono } from "hono";
|
|
8
|
+
|
|
9
|
+
import { env } from "./env.js";
|
|
10
|
+
import { resolveAgents24Principal, revokeAgents24Principal } from "./principal.js";
|
|
11
|
+
|
|
12
|
+
const client = new Agents24({
|
|
13
|
+
baseUrl: env.AGENTS24_BASE_URL,
|
|
14
|
+
apiKey: env.AGENTS24_API_KEY,
|
|
15
|
+
organizationId: env.AGENTS24_ORGANIZATION_ID,
|
|
16
|
+
projectId: env.AGENTS24_PROJECT_ID,
|
|
17
|
+
});
|
|
18
|
+
const agents24 = createAgents24BffHandler({
|
|
19
|
+
client,
|
|
20
|
+
agentId: env.AGENTS24_AGENT_ID,
|
|
21
|
+
agentVersionId: env.AGENTS24_AGENT_VERSION_ID,
|
|
22
|
+
resolvePrincipal: resolveAgents24Principal,
|
|
23
|
+
revokePrincipal: (request) => revokeAgents24Principal(request),
|
|
24
|
+
});
|
|
25
|
+
const app = new Hono();
|
|
26
|
+
|
|
27
|
+
app.use("*", async (context, next) => {
|
|
28
|
+
await next();
|
|
29
|
+
context.header("Referrer-Policy", "no-referrer");
|
|
30
|
+
context.header("Content-Security-Policy", "frame-ancestors 'none'");
|
|
31
|
+
context.header("X-Content-Type-Options", "nosniff");
|
|
32
|
+
context.header("X-Frame-Options", "DENY");
|
|
33
|
+
});
|
|
34
|
+
app.all("/api/agents24", (context) => agents24(context.req.raw));
|
|
35
|
+
app.all("/api/agents24/*", (context) => agents24(context.req.raw));
|
|
36
|
+
|
|
37
|
+
if (process.argv.includes("--production") || process.env.NODE_ENV === "production") {
|
|
38
|
+
app.use("*", serveStatic({ root: "./dist" }));
|
|
39
|
+
app.get("*", async (context) => context.html(await readFile(resolve("dist/index.html"), "utf8")));
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
serve({ fetch: app.fetch, hostname: "127.0.0.1", port: env.PORT }, (info) => {
|
|
43
|
+
process.stdout.write(`Agents24 app listening on http://127.0.0.1:${info.port}\n`);
|
|
44
|
+
});
|
|
@@ -0,0 +1,51 @@
|
|
|
1
|
+
import { createHmac, randomUUID, timingSafeEqual } from "node:crypto";
|
|
2
|
+
import type { AgentBffPrincipalResolution } from "@agents24/node/bff";
|
|
3
|
+
|
|
4
|
+
import { env } from "./env.js";
|
|
5
|
+
|
|
6
|
+
const COOKIE = "agents24_app_session";
|
|
7
|
+
const MAX_AGE = 60 * 60 * 24 * 30;
|
|
8
|
+
|
|
9
|
+
function signature(value: string): string {
|
|
10
|
+
return createHmac("sha256", env.SESSION_COOKIE_SECRET).update(value).digest("base64url");
|
|
11
|
+
}
|
|
12
|
+
|
|
13
|
+
function parseCookies(request: Request): Record<string, string> {
|
|
14
|
+
return Object.fromEntries(String(request.headers.get("cookie") || "").split(";").flatMap((part) => {
|
|
15
|
+
const pivot = part.indexOf("=");
|
|
16
|
+
if (pivot < 1) return [];
|
|
17
|
+
return [[part.slice(0, pivot).trim(), decodeURIComponent(part.slice(pivot + 1).trim())]];
|
|
18
|
+
}));
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
function verifiedId(value: string | undefined): string | null {
|
|
22
|
+
const pivot = String(value || "").lastIndexOf(".");
|
|
23
|
+
if (pivot < 1) return null;
|
|
24
|
+
const id = String(value).slice(0, pivot);
|
|
25
|
+
const supplied = Buffer.from(String(value).slice(pivot + 1));
|
|
26
|
+
const expected = Buffer.from(signature(id));
|
|
27
|
+
return supplied.length === expected.length && timingSafeEqual(supplied, expected) ? id : null;
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
function secure(request: Request): boolean {
|
|
31
|
+
return request.headers.get("x-forwarded-proto")?.split(",")[0]?.trim() === "https" || new URL(request.url).protocol === "https:";
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
function cookie(value: string, request: Request, maxAge = MAX_AGE): string {
|
|
35
|
+
return `${COOKIE}=${encodeURIComponent(value)}; Path=/; HttpOnly; SameSite=Lax; Max-Age=${maxAge}${secure(request) ? "; Secure" : ""}`;
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
// Replace this function with your application session lookup. Never accept a
|
|
39
|
+
// user ID supplied by browser request data.
|
|
40
|
+
export function resolveAgents24Principal(request: Request): AgentBffPrincipalResolution {
|
|
41
|
+
const existing = verifiedId(parseCookies(request)[COOKIE]);
|
|
42
|
+
const externalUserId = existing || randomUUID();
|
|
43
|
+
return {
|
|
44
|
+
principal: { externalUserId, externalSessionId: externalUserId },
|
|
45
|
+
...(existing ? {} : { responseHeaders: { "Set-Cookie": cookie(`${externalUserId}.${signature(externalUserId)}`, request) } }),
|
|
46
|
+
};
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
export function revokeAgents24Principal(request: Request): HeadersInit {
|
|
50
|
+
return { "Set-Cookie": cookie("", request, 0) };
|
|
51
|
+
}
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
import { AgentChatAppearanceControl, AgentChatApp } from "@agents24/chat-react/templates";
|
|
2
|
+
import { createBffAgentClient } from "@agents24/client/bff";
|
|
3
|
+
import { StrictMode } from "react";
|
|
4
|
+
import { createRoot } from "react-dom/client";
|
|
5
|
+
|
|
6
|
+
const client = createBffAgentClient({ basePath: "/api/agents24" });
|
|
7
|
+
|
|
8
|
+
function App() {
|
|
9
|
+
return (
|
|
10
|
+
<div className="app-shell" data-agents24-theme="__THEME__">
|
|
11
|
+
<AgentChatApp
|
|
12
|
+
allowAttachments
|
|
13
|
+
client={client}
|
|
14
|
+
completeMcpAuthorization={async ({ completion, serverId }) => {
|
|
15
|
+
if (completion.serverId !== serverId || !completion.connectionId) {
|
|
16
|
+
throw new Error("MCP authorization did not return the expected connection.");
|
|
17
|
+
}
|
|
18
|
+
}}
|
|
19
|
+
mcpRedirectUri={window.location.href}
|
|
20
|
+
slots={{ headerActions: <AgentChatAppearanceControl /> }}
|
|
21
|
+
/>
|
|
22
|
+
</div>
|
|
23
|
+
);
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
createRoot(document.getElementById("root")!).render(<StrictMode><App /></StrictMode>);
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
{
|
|
2
|
+
"compilerOptions": {
|
|
3
|
+
"target": "ES2022",
|
|
4
|
+
"useDefineForClassFields": true,
|
|
5
|
+
"lib": ["ES2022", "DOM", "DOM.Iterable"],
|
|
6
|
+
"allowJs": false,
|
|
7
|
+
"skipLibCheck": true,
|
|
8
|
+
"esModuleInterop": true,
|
|
9
|
+
"allowSyntheticDefaultImports": true,
|
|
10
|
+
"strict": true,
|
|
11
|
+
"forceConsistentCasingInFileNames": true,
|
|
12
|
+
"module": "ESNext",
|
|
13
|
+
"moduleResolution": "Bundler",
|
|
14
|
+
"resolveJsonModule": true,
|
|
15
|
+
"isolatedModules": true,
|
|
16
|
+
"noEmit": true,
|
|
17
|
+
"jsx": "react-jsx",
|
|
18
|
+
"types": ["vite/client", "node"]
|
|
19
|
+
},
|
|
20
|
+
"include": ["src", "server", "vite.config.ts"]
|
|
21
|
+
}
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
import { AgentChatAppearanceControl, AgentChatApp } from "@agents24/chat-react/templates";
|
|
2
|
+
import { createAnonymousSessionProvider } from "@agents24/client";
|
|
3
|
+
import { createBrowserAgentClient } from "@agents24/client/browser";
|
|
4
|
+
import { StrictMode } from "react";
|
|
5
|
+
import { createRoot } from "react-dom/client";
|
|
6
|
+
|
|
7
|
+
const baseUrl = String(import.meta.env.VITE_AGENTS24_BASE_URL || "").trim();
|
|
8
|
+
const deploymentId = String(import.meta.env.VITE_AGENTS24_DEPLOYMENT_ID || "").trim();
|
|
9
|
+
|
|
10
|
+
if (!baseUrl) throw new Error("VITE_AGENTS24_BASE_URL is required.");
|
|
11
|
+
if (!/^acd_[A-Za-z0-9_-]{10,}$/.test(deploymentId)) {
|
|
12
|
+
throw new Error("VITE_AGENTS24_DEPLOYMENT_ID must be a public acd_… deployment ID.");
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
const sessionProvider = createAnonymousSessionProvider({ baseUrl, deploymentId });
|
|
16
|
+
const client = createBrowserAgentClient({ baseUrl, deploymentId, sessionProvider });
|
|
17
|
+
|
|
18
|
+
function App() {
|
|
19
|
+
return (
|
|
20
|
+
<div className="app-shell" data-agents24-theme="__THEME__">
|
|
21
|
+
<AgentChatApp
|
|
22
|
+
allowAttachments
|
|
23
|
+
client={client}
|
|
24
|
+
mcpRedirectUri={window.location.href}
|
|
25
|
+
slots={{ headerActions: <AgentChatAppearanceControl /> }}
|
|
26
|
+
/>
|
|
27
|
+
</div>
|
|
28
|
+
);
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
createRoot(document.getElementById("root")!).render(<StrictMode><App /></StrictMode>);
|
|
@@ -0,0 +1,60 @@
|
|
|
1
|
+
[data-agents24-theme="flow"] {
|
|
2
|
+
--a24-background: #fbfaf7;
|
|
3
|
+
--a24-surface: #f0eee8;
|
|
4
|
+
--a24-surface-hover: #e8e4dc;
|
|
5
|
+
--a24-text: #252a27;
|
|
6
|
+
--a24-muted: #60675f;
|
|
7
|
+
--a24-border: rgba(55, 63, 58, .13);
|
|
8
|
+
--a24-accent: #315648;
|
|
9
|
+
--a24-accent-text: #f8fbf8;
|
|
10
|
+
--a24-focus: #668276;
|
|
11
|
+
--a24-font-family: Charter, "Bitstream Charter", "Iowan Old Style", Georgia, serif;
|
|
12
|
+
isolation: isolate;
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
:root[data-agents24-color-mode="dark"] [data-agents24-theme="flow"] {
|
|
16
|
+
--a24-background: #151916;
|
|
17
|
+
--a24-surface: #1d231f;
|
|
18
|
+
--a24-surface-hover: #283029;
|
|
19
|
+
--a24-text: #edf1ec;
|
|
20
|
+
--a24-muted: #a2aba3;
|
|
21
|
+
--a24-border: rgba(237, 241, 236, .13);
|
|
22
|
+
--a24-accent: #b9d5c6;
|
|
23
|
+
--a24-accent-text: #17231d;
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
@media (prefers-color-scheme: dark) {
|
|
27
|
+
:root:not([data-agents24-color-mode="light"]) [data-agents24-theme="flow"] {
|
|
28
|
+
--a24-background: #151916;
|
|
29
|
+
--a24-surface: #1d231f;
|
|
30
|
+
--a24-surface-hover: #283029;
|
|
31
|
+
--a24-text: #edf1ec;
|
|
32
|
+
--a24-muted: #a2aba3;
|
|
33
|
+
--a24-border: rgba(237, 241, 236, .13);
|
|
34
|
+
--a24-accent: #b9d5c6;
|
|
35
|
+
--a24-accent-text: #17231d;
|
|
36
|
+
}
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
[data-agents24-theme="flow"] .a24-chat { grid-template-columns: 17.5rem minmax(0, 1fr); }
|
|
40
|
+
[data-agents24-theme="flow"] .a24-header { min-height: 4.5rem; }
|
|
41
|
+
[data-agents24-theme="flow"] .a24-shell__content { gap: 2.4rem; max-width: 50rem; }
|
|
42
|
+
[data-agents24-theme="flow"] .a24-shell__composer-inner,
|
|
43
|
+
[data-agents24-theme="flow"] .a24-shell__empty-composer { max-width: 50rem; }
|
|
44
|
+
[data-agents24-theme="flow"] .a24-thread,
|
|
45
|
+
[data-agents24-theme="flow"] .a24-button,
|
|
46
|
+
[data-agents24-theme="flow"] .a24-icon-button,
|
|
47
|
+
[data-agents24-theme="flow"] .a24-search { border-radius: .8rem; }
|
|
48
|
+
[data-agents24-theme="flow"] .a24-composer__surface { border-radius: 1.35rem; box-shadow: 0 14px 42px rgba(42, 53, 47, .1), 0 2px 7px rgba(42, 53, 47, .07); }
|
|
49
|
+
[data-agents24-theme="flow"] .a24-composer__surface[data-expanded] { border-radius: 1.15rem; }
|
|
50
|
+
[data-agents24-theme="flow"] .a24-chat .is-user > :is([data-slot="message-content"], [data-slot="bubble-content"]) { border-radius: 1rem 1rem .3rem 1rem; }
|
|
51
|
+
[data-agents24-theme="flow"] .a24-scroller__item { animation: a24-flow-enter 260ms ease-out both; }
|
|
52
|
+
|
|
53
|
+
@keyframes a24-flow-enter {
|
|
54
|
+
from { opacity: 0; transform: translateY(.35rem); }
|
|
55
|
+
to { opacity: 1; transform: translateY(0); }
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
@media (prefers-reduced-motion: reduce) {
|
|
59
|
+
[data-agents24-theme="flow"] .a24-scroller__item { animation: none; }
|
|
60
|
+
}
|
|
@@ -0,0 +1,51 @@
|
|
|
1
|
+
[data-agents24-theme="workbench"] {
|
|
2
|
+
--a24-background: #fcfcfb;
|
|
3
|
+
--a24-surface: #f0f1ef;
|
|
4
|
+
--a24-surface-hover: #e5e7e4;
|
|
5
|
+
--a24-text: #171a18;
|
|
6
|
+
--a24-muted: #626963;
|
|
7
|
+
--a24-border: rgba(23, 26, 24, .16);
|
|
8
|
+
--a24-accent: #1f3d32;
|
|
9
|
+
--a24-accent-text: #ffffff;
|
|
10
|
+
--a24-focus: #53665d;
|
|
11
|
+
--a24-font-family: "Avenir Next", Avenir, "Segoe UI", sans-serif;
|
|
12
|
+
isolation: isolate;
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
:root[data-agents24-color-mode="dark"] [data-agents24-theme="workbench"] {
|
|
16
|
+
--a24-background: #111412;
|
|
17
|
+
--a24-surface: #191d1a;
|
|
18
|
+
--a24-surface-hover: #232925;
|
|
19
|
+
--a24-text: #eef1ee;
|
|
20
|
+
--a24-muted: #9ca69f;
|
|
21
|
+
--a24-border: rgba(238, 241, 238, .14);
|
|
22
|
+
--a24-accent: #d7e7dd;
|
|
23
|
+
--a24-accent-text: #152019;
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
@media (prefers-color-scheme: dark) {
|
|
27
|
+
:root:not([data-agents24-color-mode="light"]) [data-agents24-theme="workbench"] {
|
|
28
|
+
--a24-background: #111412;
|
|
29
|
+
--a24-surface: #191d1a;
|
|
30
|
+
--a24-surface-hover: #232925;
|
|
31
|
+
--a24-text: #eef1ee;
|
|
32
|
+
--a24-muted: #9ca69f;
|
|
33
|
+
--a24-border: rgba(238, 241, 238, .14);
|
|
34
|
+
--a24-accent: #d7e7dd;
|
|
35
|
+
--a24-accent-text: #152019;
|
|
36
|
+
}
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
[data-agents24-theme="workbench"] .a24-chat { grid-template-columns: 18rem minmax(0, 1fr); }
|
|
40
|
+
[data-agents24-theme="workbench"] .a24-sidebar__inner { padding: .625rem; }
|
|
41
|
+
[data-agents24-theme="workbench"] .a24-header { min-height: 3.5rem; padding-block: .4rem; }
|
|
42
|
+
[data-agents24-theme="workbench"] .a24-thread,
|
|
43
|
+
[data-agents24-theme="workbench"] .a24-button,
|
|
44
|
+
[data-agents24-theme="workbench"] .a24-icon-button,
|
|
45
|
+
[data-agents24-theme="workbench"] .a24-search { border-radius: .35rem; }
|
|
46
|
+
[data-agents24-theme="workbench"] .a24-shell__content { gap: 1.5rem; max-width: 54rem; padding-top: 2rem; }
|
|
47
|
+
[data-agents24-theme="workbench"] .a24-shell__composer-inner,
|
|
48
|
+
[data-agents24-theme="workbench"] .a24-shell__empty-composer { max-width: 54rem; }
|
|
49
|
+
[data-agents24-theme="workbench"] .a24-composer__surface,
|
|
50
|
+
[data-agents24-theme="workbench"] .a24-composer__surface[data-expanded] { border-radius: .65rem; box-shadow: 0 2px 8px rgba(0,0,0,.06); }
|
|
51
|
+
[data-agents24-theme="workbench"] .a24-chat .is-user > :is([data-slot="message-content"], [data-slot="bubble-content"]) { border-radius: .35rem; }
|
package/versions.json
ADDED
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
{
|
|
2
|
+
"agents24": {
|
|
3
|
+
"@agents24/client": "^0.2.0",
|
|
4
|
+
"@agents24/react": "^0.2.0",
|
|
5
|
+
"@agents24/chat-react": "^0.5.0",
|
|
6
|
+
"@agents24/node": "^0.2.0"
|
|
7
|
+
},
|
|
8
|
+
"runtime": {
|
|
9
|
+
"react": "^19.2.3",
|
|
10
|
+
"react-dom": "^19.2.3",
|
|
11
|
+
"hono": "^4.12.31",
|
|
12
|
+
"@hono/node-server": "^2.0.10"
|
|
13
|
+
},
|
|
14
|
+
"development": {
|
|
15
|
+
"@types/node": "^24.7.2",
|
|
16
|
+
"@types/react": "^19.2.3",
|
|
17
|
+
"@types/react-dom": "^19.2.3",
|
|
18
|
+
"@vitejs/plugin-react": "^6.0.3",
|
|
19
|
+
"concurrently": "^10.0.3",
|
|
20
|
+
"tsx": "^4.23.1",
|
|
21
|
+
"typescript": "^5.9.3",
|
|
22
|
+
"vite": "^8.1.5"
|
|
23
|
+
}
|
|
24
|
+
}
|