@aigentyc/chat-sdk 0.1.3 → 0.2.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/AGENTS.md +189 -0
- package/bin/doctor.mjs +255 -0
- package/dist/ai-elements.cjs +119 -162
- package/dist/ai-elements.cjs.map +1 -1
- package/dist/ai-elements.js +5 -60
- package/dist/ai-elements.js.map +1 -1
- package/dist/{chunk-PKGD6CTD.js → chunk-2677FDTG.js} +107 -59
- package/dist/chunk-2677FDTG.js.map +1 -0
- package/dist/{chunk-42ARGQXE.js → chunk-7L4FS6G7.js} +7 -3
- package/dist/chunk-7L4FS6G7.js.map +1 -0
- package/dist/{chunk-VS3NZ7FX.js → chunk-A7PCSWIK.js} +60 -5
- package/dist/chunk-A7PCSWIK.js.map +1 -0
- package/dist/{chunk-WZLWAVSS.cjs → chunk-C24QG43M.cjs} +10 -2
- package/dist/chunk-C24QG43M.cjs.map +1 -0
- package/dist/{chunk-NW2ESHRV.js → chunk-KVEJAPWA.js} +4 -8
- package/dist/chunk-KVEJAPWA.js.map +1 -0
- package/dist/{chunk-X5YEOOPK.cjs → chunk-QDFPJJ5Y.cjs} +5 -13
- package/dist/chunk-QDFPJJ5Y.cjs.map +1 -0
- package/dist/{chunk-FQN6OBGN.cjs → chunk-RTVEBPAJ.cjs} +63 -4
- package/dist/chunk-RTVEBPAJ.cjs.map +1 -0
- package/dist/{chunk-IWIGM3RY.cjs → chunk-WQARQ2FJ.cjs} +109 -61
- package/dist/chunk-WQARQ2FJ.cjs.map +1 -0
- package/dist/components.cjs +14 -14
- package/dist/components.d.cts +5 -0
- package/dist/components.d.ts +5 -0
- package/dist/components.js +4 -4
- package/dist/index.cjs +14 -12
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +8 -1
- package/dist/index.d.ts +8 -1
- package/dist/index.js +8 -6
- package/dist/index.js.map +1 -1
- package/dist/llms-full.txt +769 -0
- package/dist/ui.cjs +51 -51
- package/dist/ui.js +2 -2
- package/llms.txt +323 -0
- package/package.json +10 -2
- package/dist/chunk-42ARGQXE.js.map +0 -1
- package/dist/chunk-FQN6OBGN.cjs.map +0 -1
- package/dist/chunk-IWIGM3RY.cjs.map +0 -1
- package/dist/chunk-NW2ESHRV.js.map +0 -1
- package/dist/chunk-PKGD6CTD.js.map +0 -1
- package/dist/chunk-VS3NZ7FX.js.map +0 -1
- package/dist/chunk-WZLWAVSS.cjs.map +0 -1
- package/dist/chunk-X5YEOOPK.cjs.map +0 -1
package/AGENTS.md
ADDED
|
@@ -0,0 +1,189 @@
|
|
|
1
|
+
# AGENTS.md — @aigentyc/chat-sdk
|
|
2
|
+
|
|
3
|
+
Guide for AI coding assistants (Claude Code, Cursor, Windsurf, v0, Lovable, Bolt) using or contributing to this SDK. Humans: read `README.md` first.
|
|
4
|
+
|
|
5
|
+
**Live docs (always current):** https://context7.com/llmstxt/unpkg_aigentyc_chat-sdk_0_1_5_llms_txt/llms.txt
|
|
6
|
+
|
|
7
|
+
---
|
|
8
|
+
|
|
9
|
+
## What this package is
|
|
10
|
+
|
|
11
|
+
React 19 SDK for embedding an AI chat UI backed by the Aigentyc platform. Ships as a set of subpath exports so consumers only pull what they need.
|
|
12
|
+
|
|
13
|
+
- Package name: `@aigentyc/chat-sdk`
|
|
14
|
+
- Peer deps (required): `react>=19`, `react-dom>=19`
|
|
15
|
+
- Bundled internally (no install needed): `@ai-sdk/react`, `ai`
|
|
16
|
+
- Peer deps (optional, install only for that feature): `socket.io-client` (live chat), `recharts` (viz), `@json-render/*` + `zod` (json-render)
|
|
17
|
+
- SSR: all client components emit `"use client"`; safe for Next.js App Router.
|
|
18
|
+
|
|
19
|
+
---
|
|
20
|
+
|
|
21
|
+
## Canonical install + usage (paste-ready)
|
|
22
|
+
|
|
23
|
+
**New project?** Use the scaffolder — it's the lowest-risk path:
|
|
24
|
+
|
|
25
|
+
```bash
|
|
26
|
+
npm create aigentyc-chat@latest my-app -- --template=next --project-id=YOUR_ID
|
|
27
|
+
```
|
|
28
|
+
|
|
29
|
+
**Adding to an existing app:**
|
|
30
|
+
|
|
31
|
+
```bash
|
|
32
|
+
npm install @aigentyc/chat-sdk
|
|
33
|
+
```
|
|
34
|
+
|
|
35
|
+
```tsx
|
|
36
|
+
import { Chat } from "@aigentyc/chat-sdk"
|
|
37
|
+
import "@aigentyc/chat-sdk/theme/styles.css"
|
|
38
|
+
|
|
39
|
+
export default function Page() {
|
|
40
|
+
return (
|
|
41
|
+
<Chat
|
|
42
|
+
projectId="YOUR_PROJECT_ID"
|
|
43
|
+
apiEndpoint="https://api.aigentyc.com"
|
|
44
|
+
apiKey="YOUR_API_KEY"
|
|
45
|
+
/>
|
|
46
|
+
)
|
|
47
|
+
}
|
|
48
|
+
```
|
|
49
|
+
|
|
50
|
+
**Required:** the CSS import. Without it the chat renders unstyled.
|
|
51
|
+
|
|
52
|
+
---
|
|
53
|
+
|
|
54
|
+
## Decision tree: which API to use
|
|
55
|
+
|
|
56
|
+
```
|
|
57
|
+
Need a full chat UI with zero config? → <Chat />
|
|
58
|
+
Need a floating bubble widget? → <ChatWidget />
|
|
59
|
+
Need to customize header/input/messages only? → <Chat slots={{...}} />
|
|
60
|
+
Need custom layout around the chat? → <ChatProvider> + <ChatInterface /> + <ChatInput />
|
|
61
|
+
Need your own UI entirely? → useAigentycChat() (headless)
|
|
62
|
+
Need to override one tool's rendering? → slots.tools[toolName]
|
|
63
|
+
```
|
|
64
|
+
|
|
65
|
+
Don't reach for the headless hook just to change styling — use `theme` or `slots` first.
|
|
66
|
+
|
|
67
|
+
---
|
|
68
|
+
|
|
69
|
+
## Entry points (import from these, never from `dist/`)
|
|
70
|
+
|
|
71
|
+
| Import | What you get |
|
|
72
|
+
| --- | --- |
|
|
73
|
+
| `@aigentyc/chat-sdk` | `Chat`, `ChatWidget`, `ChatProvider` |
|
|
74
|
+
| `@aigentyc/chat-sdk/hooks` | `useAigentycChat`, other hooks |
|
|
75
|
+
| `@aigentyc/chat-sdk/components` | Granular composable chat pieces |
|
|
76
|
+
| `@aigentyc/chat-sdk/ai-elements` | `Message`, `Conversation` primitives |
|
|
77
|
+
| `@aigentyc/chat-sdk/tools` | `ToolRenderer`, `VisualizationRenderer` |
|
|
78
|
+
| `@aigentyc/chat-sdk/json-render` | json-render integration |
|
|
79
|
+
| `@aigentyc/chat-sdk/ui` | shadcn-style primitives |
|
|
80
|
+
| `@aigentyc/chat-sdk/theme` | `ThemeProvider`; CSS at `.../theme/styles.css` |
|
|
81
|
+
| `@aigentyc/chat-sdk/i18n` | `addLanguage`, built-in `en`, `he` |
|
|
82
|
+
| `@aigentyc/chat-sdk/core` | Types, transport, utilities |
|
|
83
|
+
|
|
84
|
+
---
|
|
85
|
+
|
|
86
|
+
## Slots
|
|
87
|
+
|
|
88
|
+
`slots` prop on `<Chat>` / `<ChatWidget>`:
|
|
89
|
+
|
|
90
|
+
- `header`, `welcome`, `message`, `input`, `footer`, `loader`, `suggestions`
|
|
91
|
+
- `tools`: `Record<toolName, ComponentType>` — override per-tool rendering
|
|
92
|
+
|
|
93
|
+
Each slot receives typed props — consult `.d.ts` of the entry points for exact signatures. Don't invent prop names.
|
|
94
|
+
|
|
95
|
+
---
|
|
96
|
+
|
|
97
|
+
## Tool rendering
|
|
98
|
+
|
|
99
|
+
Tool results come back from the backend with a `uiRenderMode`:
|
|
100
|
+
|
|
101
|
+
- `visualization` → recharts (requires `recharts` peer)
|
|
102
|
+
- `json_render` → `@json-render/shadcn` (requires `@json-render/*` + `zod` peers)
|
|
103
|
+
- `legacy` → HTML/CSS template from backend
|
|
104
|
+
- `preset` → built-in renderer
|
|
105
|
+
|
|
106
|
+
If a peer is missing, that tool's UI falls back; install the peer or override via `slots.tools[name]`.
|
|
107
|
+
|
|
108
|
+
---
|
|
109
|
+
|
|
110
|
+
## Theming
|
|
111
|
+
|
|
112
|
+
CSS variables scoped under `[data-aigentyc-chat]`. Two ways to customize:
|
|
113
|
+
|
|
114
|
+
```tsx
|
|
115
|
+
<Chat theme={{ primaryColor: "#3b82f6" }} />
|
|
116
|
+
```
|
|
117
|
+
|
|
118
|
+
or plain CSS targeting `[data-aigentyc-chat]`. Do **not** edit `dist/styles.css` directly.
|
|
119
|
+
|
|
120
|
+
---
|
|
121
|
+
|
|
122
|
+
## i18n
|
|
123
|
+
|
|
124
|
+
Built-in: `en`, `he`. Add more:
|
|
125
|
+
|
|
126
|
+
```tsx
|
|
127
|
+
import { addLanguage } from "@aigentyc/chat-sdk/i18n"
|
|
128
|
+
addLanguage("fr", { welcomeTitle: "Bienvenue" })
|
|
129
|
+
```
|
|
130
|
+
|
|
131
|
+
---
|
|
132
|
+
|
|
133
|
+
## Live chat handoff
|
|
134
|
+
|
|
135
|
+
```tsx
|
|
136
|
+
<Chat enableLiveChat chatServiceUrl="wss://..." />
|
|
137
|
+
```
|
|
138
|
+
|
|
139
|
+
Requires `socket.io-client`. Omit both props for AI-only mode.
|
|
140
|
+
|
|
141
|
+
---
|
|
142
|
+
|
|
143
|
+
## Rules for agents editing consumer projects
|
|
144
|
+
|
|
145
|
+
**Do:**
|
|
146
|
+
- Use the canonical quick start above verbatim for first-time setup.
|
|
147
|
+
- Import CSS once, at the app root or layout file.
|
|
148
|
+
- Prefer `slots` + `theme` before going headless.
|
|
149
|
+
- Use React 19 features (Actions, `use`) — this SDK targets React 19.
|
|
150
|
+
- Check `.d.ts` files under the published package for exact prop types.
|
|
151
|
+
|
|
152
|
+
**Don't:**
|
|
153
|
+
- Don't install React 18 — peer is `>=19`. If the project is on React 18, warn the user and stop.
|
|
154
|
+
- Don't import from `@aigentyc/chat-sdk/dist/*` — those paths are not public API.
|
|
155
|
+
- Don't reimplement message rendering when `slots.message` exists.
|
|
156
|
+
- Don't call the Aigentyc API directly from the client — the SDK owns transport.
|
|
157
|
+
- Don't add `"use client"` to files that wrap the SDK unnecessarily; it's already inside.
|
|
158
|
+
- Don't commit `apiKey` to source control; use env vars (`NEXT_PUBLIC_*` only if the project is OK exposing it; otherwise proxy through a server route).
|
|
159
|
+
|
|
160
|
+
---
|
|
161
|
+
|
|
162
|
+
## Troubleshooting quick table
|
|
163
|
+
|
|
164
|
+
| Symptom | Likely cause |
|
|
165
|
+
| --- | --- |
|
|
166
|
+
| Unstyled / broken layout | Missing `import "@aigentyc/chat-sdk/theme/styles.css"` |
|
|
167
|
+
| "Cannot find module @ai-sdk/react" | Stale install — delete `node_modules` and reinstall (these are now bundled) |
|
|
168
|
+
| Tool renders blank | Peer for that `uiRenderMode` not installed |
|
|
169
|
+
| SSR hydration warning | Wrapping `<Chat>` in a non-client component — it's fine, the SDK handles `"use client"` internally; check for other client-only code in the tree |
|
|
170
|
+
| React version error | Upgrade to React 19 |
|
|
171
|
+
|
|
172
|
+
---
|
|
173
|
+
|
|
174
|
+
## Repository layout (for contributors)
|
|
175
|
+
|
|
176
|
+
- `src/` — source; barrel files per entry point
|
|
177
|
+
- `dist/` — build output (tsup); do not edit
|
|
178
|
+
- `stories/` — Storybook
|
|
179
|
+
- `demo/` — local demo app (standalone Vite)
|
|
180
|
+
- `src/styles/index.css` — Tailwind entry compiled to `dist/styles.css`
|
|
181
|
+
|
|
182
|
+
Scripts: `pnpm build`, `pnpm storybook`, `pnpm test`, `pnpm lint`.
|
|
183
|
+
|
|
184
|
+
---
|
|
185
|
+
|
|
186
|
+
## Versioning
|
|
187
|
+
|
|
188
|
+
- Current: `0.1.0` (pre-1.0 — API may shift).
|
|
189
|
+
- Pin exact versions in consumer projects until 1.0.
|
package/bin/doctor.mjs
ADDED
|
@@ -0,0 +1,255 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
/**
|
|
3
|
+
* aigentyc doctor — diagnose Aigentyc Chat SDK install issues.
|
|
4
|
+
*
|
|
5
|
+
* Run inside a project that uses @aigentyc/chat-sdk:
|
|
6
|
+
* npx aigentyc doctor
|
|
7
|
+
*
|
|
8
|
+
* Checks (in order):
|
|
9
|
+
* 1. Node >= 18
|
|
10
|
+
* 2. React >= 19 installed
|
|
11
|
+
* 3. @aigentyc/chat-sdk installed + version
|
|
12
|
+
* 4. CSS imported somewhere in source
|
|
13
|
+
* 5. Env vars (PROJECT_ID, API_ENDPOINT) present
|
|
14
|
+
* 6. API endpoint reachable
|
|
15
|
+
* 7. API key (if present) authorized for project
|
|
16
|
+
* 8. CORS allowed-origins includes localhost dev URL (best-effort)
|
|
17
|
+
*
|
|
18
|
+
* Exit code: 0 on all-pass, 1 if any check failed.
|
|
19
|
+
*/
|
|
20
|
+
|
|
21
|
+
import { readFile, readdir, stat } from "node:fs/promises";
|
|
22
|
+
import { existsSync } from "node:fs";
|
|
23
|
+
import { resolve, join } from "node:path";
|
|
24
|
+
|
|
25
|
+
const argv = process.argv.slice(2);
|
|
26
|
+
const sub = argv[0];
|
|
27
|
+
if (sub && sub !== "doctor") {
|
|
28
|
+
console.error(`Unknown command: ${sub}\nUsage: npx aigentyc doctor`);
|
|
29
|
+
process.exit(2);
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
const CWD = process.cwd();
|
|
33
|
+
const C = {
|
|
34
|
+
dim: (s) => `\x1b[2m${s}\x1b[0m`,
|
|
35
|
+
red: (s) => `\x1b[31m${s}\x1b[0m`,
|
|
36
|
+
green: (s) => `\x1b[32m${s}\x1b[0m`,
|
|
37
|
+
yellow: (s) => `\x1b[33m${s}\x1b[0m`,
|
|
38
|
+
bold: (s) => `\x1b[1m${s}\x1b[0m`,
|
|
39
|
+
};
|
|
40
|
+
|
|
41
|
+
const results = [];
|
|
42
|
+
function pass(msg, hint) { results.push({ status: "ok", msg, hint }); }
|
|
43
|
+
function warn(msg, hint) { results.push({ status: "warn", msg, hint }); }
|
|
44
|
+
function fail(msg, hint) { results.push({ status: "fail", msg, hint }); }
|
|
45
|
+
|
|
46
|
+
// ---------------------------------------------------------------------------
|
|
47
|
+
// Helpers
|
|
48
|
+
// ---------------------------------------------------------------------------
|
|
49
|
+
|
|
50
|
+
async function readJson(path) {
|
|
51
|
+
try { return JSON.parse(await readFile(path, "utf8")); } catch { return null; }
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
async function readEnv() {
|
|
55
|
+
const candidates = [".env.local", ".env", ".env.development"];
|
|
56
|
+
const out = {};
|
|
57
|
+
for (const f of candidates) {
|
|
58
|
+
const path = join(CWD, f);
|
|
59
|
+
if (!existsSync(path)) continue;
|
|
60
|
+
const raw = await readFile(path, "utf8").catch(() => "");
|
|
61
|
+
for (const line of raw.split("\n")) {
|
|
62
|
+
const m = line.match(/^\s*([A-Z0-9_]+)\s*=\s*(.*)\s*$/);
|
|
63
|
+
if (!m) continue;
|
|
64
|
+
let v = m[2].trim();
|
|
65
|
+
if ((v.startsWith('"') && v.endsWith('"')) || (v.startsWith("'") && v.endsWith("'"))) {
|
|
66
|
+
v = v.slice(1, -1);
|
|
67
|
+
}
|
|
68
|
+
if (out[m[1]] === undefined) out[m[1]] = v;
|
|
69
|
+
}
|
|
70
|
+
}
|
|
71
|
+
return out;
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
async function* walk(dir, depth = 0) {
|
|
75
|
+
if (depth > 4) return;
|
|
76
|
+
let entries;
|
|
77
|
+
try { entries = await readdir(dir); } catch { return; }
|
|
78
|
+
for (const name of entries) {
|
|
79
|
+
if (name === "node_modules" || name === ".next" || name === "dist" || name.startsWith(".")) continue;
|
|
80
|
+
const full = join(dir, name);
|
|
81
|
+
let s;
|
|
82
|
+
try { s = await stat(full); } catch { continue; }
|
|
83
|
+
if (s.isDirectory()) {
|
|
84
|
+
yield* walk(full, depth + 1);
|
|
85
|
+
} else if (/\.(tsx?|jsx?|mjs|cjs)$/.test(name)) {
|
|
86
|
+
yield full;
|
|
87
|
+
}
|
|
88
|
+
}
|
|
89
|
+
}
|
|
90
|
+
|
|
91
|
+
async function findCssImport() {
|
|
92
|
+
for await (const file of walk(CWD)) {
|
|
93
|
+
const src = await readFile(file, "utf8").catch(() => "");
|
|
94
|
+
if (/@aigentyc\/chat-sdk\/theme\/styles\.css/.test(src)) {
|
|
95
|
+
return file;
|
|
96
|
+
}
|
|
97
|
+
}
|
|
98
|
+
return null;
|
|
99
|
+
}
|
|
100
|
+
|
|
101
|
+
function semverMajor(v) {
|
|
102
|
+
if (!v) return 0;
|
|
103
|
+
const m = String(v).match(/(\d+)/);
|
|
104
|
+
return m ? Number(m[1]) : 0;
|
|
105
|
+
}
|
|
106
|
+
|
|
107
|
+
async function pingEndpoint(url) {
|
|
108
|
+
const ctrl = new AbortController();
|
|
109
|
+
const t = setTimeout(() => ctrl.abort(), 5000);
|
|
110
|
+
try {
|
|
111
|
+
const res = await fetch(url, { method: "GET", signal: ctrl.signal });
|
|
112
|
+
clearTimeout(t);
|
|
113
|
+
return { ok: res.ok || res.status < 500, status: res.status };
|
|
114
|
+
} catch (err) {
|
|
115
|
+
clearTimeout(t);
|
|
116
|
+
return { ok: false, error: String(err?.message || err) };
|
|
117
|
+
}
|
|
118
|
+
}
|
|
119
|
+
|
|
120
|
+
// ---------------------------------------------------------------------------
|
|
121
|
+
// Checks
|
|
122
|
+
// ---------------------------------------------------------------------------
|
|
123
|
+
|
|
124
|
+
async function run() {
|
|
125
|
+
console.log(C.bold("\n aigentyc doctor"));
|
|
126
|
+
console.log(C.dim(` cwd: ${CWD}\n`));
|
|
127
|
+
|
|
128
|
+
// 1. Node version
|
|
129
|
+
const nodeMajor = Number(process.versions.node.split(".")[0]);
|
|
130
|
+
if (nodeMajor >= 18) pass(`Node ${process.versions.node}`);
|
|
131
|
+
else fail(`Node ${process.versions.node} (need >= 18)`, "Update Node: https://nodejs.org");
|
|
132
|
+
|
|
133
|
+
// 2. package.json + React + SDK
|
|
134
|
+
const pkg = await readJson(join(CWD, "package.json"));
|
|
135
|
+
if (!pkg) {
|
|
136
|
+
fail("No package.json found in current directory.", `Run from your project root.`);
|
|
137
|
+
return finish();
|
|
138
|
+
}
|
|
139
|
+
const deps = { ...pkg.dependencies, ...pkg.devDependencies };
|
|
140
|
+
|
|
141
|
+
const reactV = deps.react;
|
|
142
|
+
if (!reactV) fail("`react` not in dependencies.", "npm install react@^19 react-dom@^19");
|
|
143
|
+
else if (semverMajor(reactV) < 19)
|
|
144
|
+
fail(`React ${reactV} (need >= 19)`, "npm install react@^19 react-dom@^19");
|
|
145
|
+
else pass(`React ${reactV}`);
|
|
146
|
+
|
|
147
|
+
const sdkV = deps["@aigentyc/chat-sdk"];
|
|
148
|
+
if (!sdkV) {
|
|
149
|
+
fail("`@aigentyc/chat-sdk` not in dependencies.", "npm install @aigentyc/chat-sdk");
|
|
150
|
+
} else {
|
|
151
|
+
pass(`@aigentyc/chat-sdk ${sdkV}`);
|
|
152
|
+
}
|
|
153
|
+
|
|
154
|
+
// 3. CSS import
|
|
155
|
+
const cssFile = await findCssImport();
|
|
156
|
+
if (cssFile) pass(`CSS imported in ${cssFile.replace(CWD + "/", "")}`);
|
|
157
|
+
else fail(
|
|
158
|
+
"Missing CSS import.",
|
|
159
|
+
`Add to your entry/layout file:\n import "@aigentyc/chat-sdk/theme/styles.css"`
|
|
160
|
+
);
|
|
161
|
+
|
|
162
|
+
// 4. Env vars
|
|
163
|
+
const env = await readEnv();
|
|
164
|
+
const isNext = !!deps.next;
|
|
165
|
+
const prefix = isNext ? "NEXT_PUBLIC_AIGENTYC" : "VITE_AIGENTYC";
|
|
166
|
+
|
|
167
|
+
const projectId = env[`${prefix}_PROJECT_ID`];
|
|
168
|
+
const apiEndpoint = env[`${prefix}_API_ENDPOINT`];
|
|
169
|
+
const apiKey = env[`${prefix}_API_KEY`];
|
|
170
|
+
|
|
171
|
+
if (!projectId || projectId === "replace-me") {
|
|
172
|
+
fail(
|
|
173
|
+
`${prefix}_PROJECT_ID missing or placeholder.`,
|
|
174
|
+
"Get your projectId from https://app.aigentyc.ai/dashboard"
|
|
175
|
+
);
|
|
176
|
+
} else if (!/^proj_/.test(projectId)) {
|
|
177
|
+
warn(
|
|
178
|
+
`${prefix}_PROJECT_ID does not look like a project slug (expected proj_...).`,
|
|
179
|
+
`Got: ${projectId}`
|
|
180
|
+
);
|
|
181
|
+
} else {
|
|
182
|
+
pass(`${prefix}_PROJECT_ID = ${projectId}`);
|
|
183
|
+
}
|
|
184
|
+
|
|
185
|
+
if (!apiEndpoint) {
|
|
186
|
+
fail(
|
|
187
|
+
`${prefix}_API_ENDPOINT missing.`,
|
|
188
|
+
`Add ${prefix}_API_ENDPOINT=https://app.aigentyc.ai`
|
|
189
|
+
);
|
|
190
|
+
} else {
|
|
191
|
+
pass(`${prefix}_API_ENDPOINT = ${apiEndpoint}`);
|
|
192
|
+
}
|
|
193
|
+
|
|
194
|
+
if (apiKey) {
|
|
195
|
+
if (!/^tyco_pk_/.test(apiKey)) {
|
|
196
|
+
warn(
|
|
197
|
+
`${prefix}_API_KEY does not look like an Aigentyc key (expected tyco_pk_...).`,
|
|
198
|
+
`Got: ${apiKey.slice(0, 12)}...`
|
|
199
|
+
);
|
|
200
|
+
} else {
|
|
201
|
+
pass(`${prefix}_API_KEY = ${apiKey.slice(0, 12)}...`);
|
|
202
|
+
}
|
|
203
|
+
} else {
|
|
204
|
+
warn(
|
|
205
|
+
`${prefix}_API_KEY not set.`,
|
|
206
|
+
"OK if your project is public; required otherwise. Create one at https://app.aigentyc.ai/dashboard/<projectId>/api-keys"
|
|
207
|
+
);
|
|
208
|
+
}
|
|
209
|
+
|
|
210
|
+
// 5. Endpoint reachable
|
|
211
|
+
if (apiEndpoint) {
|
|
212
|
+
const ping = await pingEndpoint(apiEndpoint);
|
|
213
|
+
if (ping.ok) pass(`Reachable: ${apiEndpoint} (HTTP ${ping.status})`);
|
|
214
|
+
else fail(
|
|
215
|
+
`Cannot reach ${apiEndpoint}`,
|
|
216
|
+
ping.error ? `Network error: ${ping.error}` : `HTTP ${ping.status}`
|
|
217
|
+
);
|
|
218
|
+
}
|
|
219
|
+
|
|
220
|
+
// 6. CORS hint
|
|
221
|
+
const dev = isNext ? "http://localhost:3000" : "http://localhost:5173";
|
|
222
|
+
warn(
|
|
223
|
+
"CORS",
|
|
224
|
+
`Make sure your API key allows origin: ${dev} (set in dashboard → API Keys → Allowed Origins)`
|
|
225
|
+
);
|
|
226
|
+
|
|
227
|
+
finish();
|
|
228
|
+
}
|
|
229
|
+
|
|
230
|
+
function finish() {
|
|
231
|
+
console.log("");
|
|
232
|
+
let failed = 0;
|
|
233
|
+
for (const r of results) {
|
|
234
|
+
const tag =
|
|
235
|
+
r.status === "ok" ? C.green("✓") :
|
|
236
|
+
r.status === "warn" ? C.yellow("⚠") :
|
|
237
|
+
C.red("✗");
|
|
238
|
+
console.log(` ${tag} ${r.msg}`);
|
|
239
|
+
if (r.hint && r.status !== "ok") {
|
|
240
|
+
console.log(` ${C.dim(r.hint)}`);
|
|
241
|
+
}
|
|
242
|
+
if (r.status === "fail") failed++;
|
|
243
|
+
}
|
|
244
|
+
console.log("");
|
|
245
|
+
if (failed === 0) {
|
|
246
|
+
console.log(C.green(" All checks passed."));
|
|
247
|
+
console.log(C.dim(" Run `npm run dev` and your chat should work.\n"));
|
|
248
|
+
process.exit(0);
|
|
249
|
+
} else {
|
|
250
|
+
console.log(C.red(` ${failed} check${failed === 1 ? "" : "s"} failed. Fix the items above and rerun.\n`));
|
|
251
|
+
process.exit(1);
|
|
252
|
+
}
|
|
253
|
+
}
|
|
254
|
+
|
|
255
|
+
run();
|