@cometchat/skills-cli 2.0.3 → 2.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/bin/cometchat.mjs +12 -6
- package/dist/index.js +5472 -1544
- package/dist/registry/schemas/config.schema.json +119 -0
- package/dist/registry/v6/experiences/1-conversation-list/reactjs-dedicated-route.template.json +81 -0
- package/dist/registry/v6/experiences/1-conversation-list/templates/reactjs-dedicated-route/ChatPage.tsx.tpl +87 -0
- package/dist/registry/v6/experiences/1-conversation-list/templates/reactjs-dedicated-route/CometChatMessenger.css.tpl +20 -0
- package/dist/registry/v6/experiences/1-conversation-list/templates/reactjs-dedicated-route/CometChatMessenger.tsx.tpl +54 -0
- package/dist/registry/v6/experiences/1-conversation-list/templates/reactjs-dedicated-route/CometChatSelector.tsx.tpl +40 -0
- package/dist/registry/v6/experiences/2-one-to-one/reactjs-dedicated-route.template.json +75 -0
- package/dist/registry/v6/experiences/2-one-to-one/reactjs.template.json +6 -3
- package/dist/registry/v6/experiences/2-one-to-one/templates/reactjs-dedicated-route/ChatPage.tsx.tpl +84 -0
- package/dist/registry/v6/experiences/2-one-to-one/templates/reactjs-dedicated-route/CometChatMessenger.css.tpl +9 -0
- package/dist/registry/v6/experiences/2-one-to-one/templates/reactjs-dedicated-route/CometChatMessenger.tsx.tpl +43 -0
- package/dist/registry/v6/experiences/3-tab-based/reactjs-dedicated-route.template.json +89 -0
- package/dist/registry/v6/experiences/3-tab-based/reactjs.template.json +6 -3
- package/dist/registry/v6/experiences/3-tab-based/templates/reactjs-dedicated-route/ChatPage.tsx.tpl +84 -0
- package/dist/registry/v6/experiences/3-tab-based/templates/reactjs-dedicated-route/CometChatMessenger.css.tpl +11 -0
- package/dist/registry/v6/experiences/3-tab-based/templates/reactjs-dedicated-route/CometChatMessenger.tsx.tpl +61 -0
- package/dist/registry/v6/experiences/3-tab-based/templates/reactjs-dedicated-route/CometChatTabs.css.tpl +43 -0
- package/dist/registry/v6/experiences/3-tab-based/templates/reactjs-dedicated-route/CometChatTabs.tsx.tpl +72 -0
- package/dist/utils/error-dictionary.js +170 -0
- package/dist/utils/onboarding-options.js +30 -0
- package/package.json +11 -4
|
@@ -0,0 +1,89 @@
|
|
|
1
|
+
{
|
|
2
|
+
"$schema": "../../../schemas/template.schema.json",
|
|
3
|
+
"version": "1.0.0",
|
|
4
|
+
"experience_id": 3,
|
|
5
|
+
"framework": "reactjs-dedicated-route",
|
|
6
|
+
"sdk_compatibility": ">=6.0.0 <7.0.0",
|
|
7
|
+
"default_placement": "dedicated-route",
|
|
8
|
+
"deps": [
|
|
9
|
+
{ "name": "@cometchat/chat-uikit-react", "version": "^6" },
|
|
10
|
+
{ "name": "@cometchat/chat-sdk-javascript", "version": "^4" }
|
|
11
|
+
],
|
|
12
|
+
"env_vars": [
|
|
13
|
+
{ "name": "{{ENV_PREFIX}}COMETCHAT_APP_ID", "required": true, "description": "CometChat App ID from your dashboard" },
|
|
14
|
+
{ "name": "{{ENV_PREFIX}}COMETCHAT_REGION", "required": true, "description": "CometChat region (us, eu, in, etc.)" },
|
|
15
|
+
{ "name": "{{ENV_PREFIX}}COMETCHAT_AUTH_KEY", "required": true, "secret": true, "description": "CometChat Auth Key (development only — use auth tokens in production)" }
|
|
16
|
+
],
|
|
17
|
+
"files": [
|
|
18
|
+
{
|
|
19
|
+
"path": "src/cometchat/CometChatTabs.tsx",
|
|
20
|
+
"action": "create",
|
|
21
|
+
"template_ref": "CometChatTabs.tsx.tpl",
|
|
22
|
+
"owned": true
|
|
23
|
+
},
|
|
24
|
+
{
|
|
25
|
+
"path": "src/cometchat/CometChatTabs.css",
|
|
26
|
+
"action": "create",
|
|
27
|
+
"template_ref": "CometChatTabs.css.tpl",
|
|
28
|
+
"owned": true
|
|
29
|
+
},
|
|
30
|
+
{
|
|
31
|
+
"path": "src/cometchat/CometChatMessenger.tsx",
|
|
32
|
+
"action": "create",
|
|
33
|
+
"template_ref": "CometChatMessenger.tsx.tpl",
|
|
34
|
+
"owned": true
|
|
35
|
+
},
|
|
36
|
+
{
|
|
37
|
+
"path": "src/cometchat/CometChatMessenger.css",
|
|
38
|
+
"action": "create",
|
|
39
|
+
"template_ref": "CometChatMessenger.css.tpl",
|
|
40
|
+
"owned": true
|
|
41
|
+
},
|
|
42
|
+
{
|
|
43
|
+
"path": "src/pages/ChatPage.tsx",
|
|
44
|
+
"action": "create",
|
|
45
|
+
"template_ref": "ChatPage.tsx.tpl",
|
|
46
|
+
"owned": true,
|
|
47
|
+
"is_entry": true
|
|
48
|
+
},
|
|
49
|
+
{
|
|
50
|
+
"path": "src/App.tsx",
|
|
51
|
+
"action": "patch",
|
|
52
|
+
"patch_mode": "prepend",
|
|
53
|
+
"patch_content": "import ChatPage from \"./pages/ChatPage\";\n",
|
|
54
|
+
"skip_if_exists": "./pages/ChatPage",
|
|
55
|
+
"embed_skip": true
|
|
56
|
+
},
|
|
57
|
+
{
|
|
58
|
+
"path": "src/App.tsx",
|
|
59
|
+
"action": "patch",
|
|
60
|
+
"patch_mode": "insert-before",
|
|
61
|
+
"anchor": "</Routes>",
|
|
62
|
+
"patch_content": " <Route path=\"{{PLACEMENT_PATH}}\" element={<ChatPage />} />\n ",
|
|
63
|
+
"skip_if_exists": "element={<ChatPage />}",
|
|
64
|
+
"embed_skip": true
|
|
65
|
+
},
|
|
66
|
+
{
|
|
67
|
+
"path": "src/index.css",
|
|
68
|
+
"action": "patch",
|
|
69
|
+
"patch_mode": "prepend",
|
|
70
|
+
"patch_content": "@import url(\"@cometchat/chat-uikit-react/css-variables.css\");\n",
|
|
71
|
+
"skip_if_exists": "@cometchat/chat-uikit-react/css-variables.css"
|
|
72
|
+
}
|
|
73
|
+
],
|
|
74
|
+
"verify_rules": [
|
|
75
|
+
"css_variables_imported_once",
|
|
76
|
+
"init_before_login",
|
|
77
|
+
"no_user_and_group_same_component",
|
|
78
|
+
"no_auth_key_in_source",
|
|
79
|
+
"render_gated_on_login_resolve",
|
|
80
|
+
"error_ui_visible_on_failure"
|
|
81
|
+
],
|
|
82
|
+
"next_steps": [
|
|
83
|
+
"Run `npm run dev` to start the dev server",
|
|
84
|
+
"Visit http://localhost:5173{{PLACEMENT_PATH}}",
|
|
85
|
+
"The left panel shows the tab bar (Chats / Calls / Users / Groups). Click any tab to switch.",
|
|
86
|
+
"Click a conversation, user, or group to open the message thread on the right.",
|
|
87
|
+
"If the route didn't wire up automatically (your App.tsx layout is non-standard), add: <Route path=\"{{PLACEMENT_PATH}}\" element={<ChatPage />} /> inside your existing <Routes> block and import ChatPage from ./pages/ChatPage"
|
|
88
|
+
]
|
|
89
|
+
}
|
|
@@ -38,19 +38,22 @@
|
|
|
38
38
|
"path": "src/main.tsx",
|
|
39
39
|
"action": "create",
|
|
40
40
|
"template_ref": "main.tsx.tpl",
|
|
41
|
-
"owned": true
|
|
41
|
+
"owned": true,
|
|
42
|
+
"embed_skip": true
|
|
42
43
|
},
|
|
43
44
|
{
|
|
44
45
|
"path": "src/App.tsx",
|
|
45
46
|
"action": "create",
|
|
46
47
|
"template_ref": "App.tsx.tpl",
|
|
47
|
-
"owned": true
|
|
48
|
+
"owned": true,
|
|
49
|
+
"is_entry": true
|
|
48
50
|
},
|
|
49
51
|
{
|
|
50
52
|
"path": "src/App.css",
|
|
51
53
|
"action": "create",
|
|
52
54
|
"template_ref": "App.css.tpl",
|
|
53
|
-
"owned": true
|
|
55
|
+
"owned": true,
|
|
56
|
+
"move_with_entry": true
|
|
54
57
|
},
|
|
55
58
|
{
|
|
56
59
|
"path": "src/cometchat/CometChatTabs.tsx",
|
package/dist/registry/v6/experiences/3-tab-based/templates/reactjs-dedicated-route/ChatPage.tsx.tpl
ADDED
|
@@ -0,0 +1,84 @@
|
|
|
1
|
+
import { lazy, Suspense, useEffect, useState } from "react";
|
|
2
|
+
import {
|
|
3
|
+
CometChatUIKit,
|
|
4
|
+
UIKitSettingsBuilder,
|
|
5
|
+
} from "@cometchat/chat-uikit-react";
|
|
6
|
+
|
|
7
|
+
const CometChatMessenger = lazy(
|
|
8
|
+
() => import("../cometchat/CometChatMessenger")
|
|
9
|
+
);
|
|
10
|
+
|
|
11
|
+
const COMETCHAT_CONSTANTS = {
|
|
12
|
+
APP_ID: import.meta.env.{{ENV_PREFIX}}COMETCHAT_APP_ID as string,
|
|
13
|
+
REGION: import.meta.env.{{ENV_PREFIX}}COMETCHAT_REGION as string,
|
|
14
|
+
AUTH_KEY: import.meta.env.{{ENV_PREFIX}}COMETCHAT_AUTH_KEY as string,
|
|
15
|
+
};
|
|
16
|
+
|
|
17
|
+
const settings = new UIKitSettingsBuilder()
|
|
18
|
+
.setAppId(COMETCHAT_CONSTANTS.APP_ID)
|
|
19
|
+
.setRegion(COMETCHAT_CONSTANTS.REGION)
|
|
20
|
+
.setAuthKey(COMETCHAT_CONSTANTS.AUTH_KEY)
|
|
21
|
+
.subscribePresenceForAllUsers()
|
|
22
|
+
.build();
|
|
23
|
+
|
|
24
|
+
let initPromise: Promise<void> | null = null;
|
|
25
|
+
function ensureInitialized(): Promise<void> {
|
|
26
|
+
if (initPromise) return initPromise;
|
|
27
|
+
initPromise = CometChatUIKit.init(settings)
|
|
28
|
+
.then(() => CometChatUIKit.getLoggedinUser())
|
|
29
|
+
.then((user) => {
|
|
30
|
+
if (user) return undefined;
|
|
31
|
+
return CometChatUIKit.login("{{LOGIN_UID}}").then(() => undefined);
|
|
32
|
+
})
|
|
33
|
+
.then(() => undefined);
|
|
34
|
+
return initPromise;
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
export default function ChatPage() {
|
|
38
|
+
const [ready, setReady] = useState(false);
|
|
39
|
+
const [error, setError] = useState<string | null>(null);
|
|
40
|
+
|
|
41
|
+
useEffect(() => {
|
|
42
|
+
let cancelled = false;
|
|
43
|
+
ensureInitialized()
|
|
44
|
+
.then(() => {
|
|
45
|
+
if (!cancelled) setReady(true);
|
|
46
|
+
})
|
|
47
|
+
.catch((e: unknown) => {
|
|
48
|
+
if (!cancelled) setError(String(e));
|
|
49
|
+
});
|
|
50
|
+
return () => {
|
|
51
|
+
cancelled = true;
|
|
52
|
+
};
|
|
53
|
+
}, []);
|
|
54
|
+
|
|
55
|
+
if (error) {
|
|
56
|
+
return (
|
|
57
|
+
<div
|
|
58
|
+
className="cometchat-page"
|
|
59
|
+
style={{
|
|
60
|
+
color: "red",
|
|
61
|
+
padding: 16,
|
|
62
|
+
fontFamily: "monospace",
|
|
63
|
+
}}
|
|
64
|
+
>
|
|
65
|
+
CometChat failed to load: {error}
|
|
66
|
+
</div>
|
|
67
|
+
);
|
|
68
|
+
}
|
|
69
|
+
if (!ready) {
|
|
70
|
+
return (
|
|
71
|
+
<div className="cometchat-page" style={{ padding: 16 }}>
|
|
72
|
+
Loading chat…
|
|
73
|
+
</div>
|
|
74
|
+
);
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
return (
|
|
78
|
+
<div className="cometchat-page">
|
|
79
|
+
<Suspense fallback={<div style={{ padding: 16 }}>Loading chat…</div>}>
|
|
80
|
+
<CometChatMessenger />
|
|
81
|
+
</Suspense>
|
|
82
|
+
</div>
|
|
83
|
+
);
|
|
84
|
+
}
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
/* Scoped to .cometchat-page (root div in ChatPage.tsx). The tabbed messenger
|
|
2
|
+
* needs resolved height on every ancestor — see the exp 1 dedicated-route CSS
|
|
3
|
+
* for the full rationale.
|
|
4
|
+
*/
|
|
5
|
+
.cometchat-page { width: 100vw; height: 100vh; }
|
|
6
|
+
.conversations-with-messages { display: flex; height: 100%; width: 100%; }
|
|
7
|
+
.conversations-wrapper { height: 100vh; width: 480px; overflow: hidden; display: flex; flex-direction: column; flex-shrink: 0; }
|
|
8
|
+
.conversations-wrapper > .cometchat { overflow: hidden; }
|
|
9
|
+
.messages-wrapper { flex: 1; min-width: 0; height: 100%; display: flex; flex-direction: column; }
|
|
10
|
+
.empty-conversation { height: 100vh; width: 100%; display: flex; justify-content: center; align-items: center; background: var(--cometchat-background-color-03, #F5F5F5); color: var(--cometchat-text-color-secondary, #727272); font: var(--cometchat-font-body-regular, 400 14px Roboto); }
|
|
11
|
+
.cometchat .cometchat-message-composer { border-radius: 0; }
|
|
@@ -0,0 +1,61 @@
|
|
|
1
|
+
import { useState } from "react";
|
|
2
|
+
import {
|
|
3
|
+
CometChatMessageComposer,
|
|
4
|
+
CometChatMessageHeader,
|
|
5
|
+
CometChatMessageList,
|
|
6
|
+
} from "@cometchat/chat-uikit-react";
|
|
7
|
+
import { CometChat } from "@cometchat/chat-sdk-javascript";
|
|
8
|
+
import { CometChatTabs, type CometChatTab } from "./CometChatTabs";
|
|
9
|
+
import "./CometChatMessenger.css";
|
|
10
|
+
|
|
11
|
+
export default function CometChatMessenger() {
|
|
12
|
+
const [activeTab, setActiveTab] = useState<CometChatTab>("chats");
|
|
13
|
+
const [selectedUser, setSelectedUser] = useState<
|
|
14
|
+
CometChat.User | undefined
|
|
15
|
+
>();
|
|
16
|
+
const [selectedGroup, setSelectedGroup] = useState<
|
|
17
|
+
CometChat.Group | undefined
|
|
18
|
+
>();
|
|
19
|
+
|
|
20
|
+
const handleSelectorItemClicked = (
|
|
21
|
+
activeItem: CometChat.Conversation | CometChat.User | CometChat.Group,
|
|
22
|
+
) => {
|
|
23
|
+
const item =
|
|
24
|
+
activeItem instanceof CometChat.Conversation
|
|
25
|
+
? activeItem.getConversationWith()
|
|
26
|
+
: activeItem;
|
|
27
|
+
if (item instanceof CometChat.User) {
|
|
28
|
+
setSelectedUser(item);
|
|
29
|
+
setSelectedGroup(undefined);
|
|
30
|
+
} else if (item instanceof CometChat.Group) {
|
|
31
|
+
setSelectedUser(undefined);
|
|
32
|
+
setSelectedGroup(item);
|
|
33
|
+
}
|
|
34
|
+
};
|
|
35
|
+
|
|
36
|
+
return (
|
|
37
|
+
<div className="conversations-with-messages">
|
|
38
|
+
<div className="conversations-wrapper">
|
|
39
|
+
<CometChatTabs
|
|
40
|
+
activeTab={activeTab}
|
|
41
|
+
onTabChange={setActiveTab}
|
|
42
|
+
onItemClick={handleSelectorItemClicked}
|
|
43
|
+
/>
|
|
44
|
+
</div>
|
|
45
|
+
{selectedUser || selectedGroup ? (
|
|
46
|
+
<div className="messages-wrapper">
|
|
47
|
+
{selectedUser && <CometChatMessageHeader user={selectedUser} />}
|
|
48
|
+
{selectedGroup && <CometChatMessageHeader group={selectedGroup} />}
|
|
49
|
+
{selectedUser && <CometChatMessageList user={selectedUser} />}
|
|
50
|
+
{selectedGroup && <CometChatMessageList group={selectedGroup} />}
|
|
51
|
+
{selectedUser && <CometChatMessageComposer user={selectedUser} />}
|
|
52
|
+
{selectedGroup && <CometChatMessageComposer group={selectedGroup} />}
|
|
53
|
+
</div>
|
|
54
|
+
) : (
|
|
55
|
+
<div className="empty-conversation">
|
|
56
|
+
Select a conversation to start chatting
|
|
57
|
+
</div>
|
|
58
|
+
)}
|
|
59
|
+
</div>
|
|
60
|
+
);
|
|
61
|
+
}
|
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
.cometchat-tabs {
|
|
2
|
+
height: 100%;
|
|
3
|
+
width: 100%;
|
|
4
|
+
display: flex;
|
|
5
|
+
flex-direction: column;
|
|
6
|
+
}
|
|
7
|
+
|
|
8
|
+
.cometchat-tabs-content {
|
|
9
|
+
flex: 1;
|
|
10
|
+
overflow: hidden;
|
|
11
|
+
display: flex;
|
|
12
|
+
flex-direction: column;
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
.cometchat-tabs-content > .cometchat {
|
|
16
|
+
flex: 1;
|
|
17
|
+
overflow: hidden;
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
.cometchat-tabs-bar {
|
|
21
|
+
display: flex;
|
|
22
|
+
border-top: 1px solid var(--cometchat-border-color-default, #e8e8e8);
|
|
23
|
+
background: var(--cometchat-background-color-01, #ffffff);
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
.cometchat-tabs-bar-tab {
|
|
27
|
+
flex: 1;
|
|
28
|
+
padding: 12px 8px;
|
|
29
|
+
border: none;
|
|
30
|
+
background: transparent;
|
|
31
|
+
font: var(--cometchat-font-body-regular, 400 14px Roboto);
|
|
32
|
+
color: var(--cometchat-text-color-secondary, #727272);
|
|
33
|
+
cursor: pointer;
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
.cometchat-tabs-bar-tab.active {
|
|
37
|
+
color: var(--cometchat-primary-color, #6852d6);
|
|
38
|
+
font-weight: 600;
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
.cometchat-tabs-bar-tab:hover {
|
|
42
|
+
background: var(--cometchat-background-color-02, #f8f8f8);
|
|
43
|
+
}
|
|
@@ -0,0 +1,72 @@
|
|
|
1
|
+
import { useEffect, useState } from "react";
|
|
2
|
+
import { CometChat } from "@cometchat/chat-sdk-javascript";
|
|
3
|
+
import {
|
|
4
|
+
CometChatCallLogs,
|
|
5
|
+
CometChatConversations,
|
|
6
|
+
CometChatGroups,
|
|
7
|
+
CometChatUIKitLoginListener,
|
|
8
|
+
CometChatUsers,
|
|
9
|
+
} from "@cometchat/chat-uikit-react";
|
|
10
|
+
import "./CometChatTabs.css";
|
|
11
|
+
|
|
12
|
+
export type CometChatTab = "chats" | "calls" | "users" | "groups";
|
|
13
|
+
|
|
14
|
+
interface CometChatTabsProps {
|
|
15
|
+
activeTab: CometChatTab;
|
|
16
|
+
onTabChange: (tab: CometChatTab) => void;
|
|
17
|
+
onItemClick: (
|
|
18
|
+
item: CometChat.Conversation | CometChat.User | CometChat.Group,
|
|
19
|
+
) => void;
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
const TABS: { id: CometChatTab; label: string }[] = [
|
|
23
|
+
{ id: "chats", label: "Chats" },
|
|
24
|
+
{ id: "calls", label: "Calls" },
|
|
25
|
+
{ id: "users", label: "Users" },
|
|
26
|
+
{ id: "groups", label: "Groups" },
|
|
27
|
+
];
|
|
28
|
+
|
|
29
|
+
export const CometChatTabs = ({
|
|
30
|
+
activeTab,
|
|
31
|
+
onTabChange,
|
|
32
|
+
onItemClick,
|
|
33
|
+
}: CometChatTabsProps) => {
|
|
34
|
+
const [loggedInUser, setLoggedInUser] = useState<CometChat.User | null>(null);
|
|
35
|
+
|
|
36
|
+
useEffect(() => {
|
|
37
|
+
setLoggedInUser(CometChatUIKitLoginListener.getLoggedInUser());
|
|
38
|
+
}, []);
|
|
39
|
+
|
|
40
|
+
if (!loggedInUser) return null;
|
|
41
|
+
|
|
42
|
+
return (
|
|
43
|
+
<div className="cometchat-tabs">
|
|
44
|
+
<div className="cometchat-tabs-content">
|
|
45
|
+
{activeTab === "chats" && (
|
|
46
|
+
<CometChatConversations
|
|
47
|
+
onItemClick={(c) => onItemClick(c)}
|
|
48
|
+
/>
|
|
49
|
+
)}
|
|
50
|
+
{activeTab === "calls" && <CometChatCallLogs />}
|
|
51
|
+
{activeTab === "users" && (
|
|
52
|
+
<CometChatUsers onItemClick={(u) => onItemClick(u)} />
|
|
53
|
+
)}
|
|
54
|
+
{activeTab === "groups" && (
|
|
55
|
+
<CometChatGroups onItemClick={(g) => onItemClick(g)} />
|
|
56
|
+
)}
|
|
57
|
+
</div>
|
|
58
|
+
<nav className="cometchat-tabs-bar">
|
|
59
|
+
{TABS.map((tab) => (
|
|
60
|
+
<button
|
|
61
|
+
key={tab.id}
|
|
62
|
+
type="button"
|
|
63
|
+
className={`cometchat-tabs-bar-tab${activeTab === tab.id ? " active" : ""}`}
|
|
64
|
+
onClick={() => onTabChange(tab.id)}
|
|
65
|
+
>
|
|
66
|
+
{tab.label}
|
|
67
|
+
</button>
|
|
68
|
+
))}
|
|
69
|
+
</nav>
|
|
70
|
+
</div>
|
|
71
|
+
);
|
|
72
|
+
};
|
|
@@ -0,0 +1,170 @@
|
|
|
1
|
+
const DICTIONARY = {
|
|
2
|
+
ERR_EMAIL_ALREADY_EXISTS: {
|
|
3
|
+
humanMessage: "An account with this email already exists.",
|
|
4
|
+
suggestion: "Go back and pick 'Sign in' instead, or use a different email.",
|
|
5
|
+
retryable: false
|
|
6
|
+
},
|
|
7
|
+
ERR_INVALID_VERIFICATION_CODE: {
|
|
8
|
+
humanMessage: "That verification code is invalid or expired.",
|
|
9
|
+
suggestion: "Check your inbox for the latest email and paste the full code or link again. Codes typically expire after 15 minutes.",
|
|
10
|
+
retryable: true
|
|
11
|
+
},
|
|
12
|
+
AUTH_ERR_INVALID_CREDENTIALS: {
|
|
13
|
+
humanMessage: "Email or password is incorrect.",
|
|
14
|
+
suggestion: "Try again, or use 'Create a new account' if you don't have one.",
|
|
15
|
+
retryable: true
|
|
16
|
+
},
|
|
17
|
+
AUTH_FAILED: {
|
|
18
|
+
humanMessage: "Authentication failed.",
|
|
19
|
+
suggestion: "Your session may have expired. Sign in again.",
|
|
20
|
+
retryable: true
|
|
21
|
+
},
|
|
22
|
+
OTP_REQUIRED: {
|
|
23
|
+
humanMessage: "Two-factor authentication is enabled on this account.",
|
|
24
|
+
suggestion: "Enter the verification code from your email when prompted.",
|
|
25
|
+
retryable: true
|
|
26
|
+
},
|
|
27
|
+
AUTH_ERR_TOKEN_BLACKLISTED: {
|
|
28
|
+
humanMessage: "Your session has been revoked.",
|
|
29
|
+
suggestion: "Run `cometchat auth login` again to re-authenticate.",
|
|
30
|
+
retryable: false
|
|
31
|
+
},
|
|
32
|
+
ERR_NO_INTEGRATION: {
|
|
33
|
+
humanMessage: "CometChat isn't installed in this project yet.",
|
|
34
|
+
suggestion: "Run `cometchat apply` first (or restart the wizard from the beginning) to create the base integration, then come back to this step.",
|
|
35
|
+
retryable: false
|
|
36
|
+
},
|
|
37
|
+
ERR_UNSUPPORTED_FRAMEWORK: {
|
|
38
|
+
humanMessage: "This step isn't available for your framework.",
|
|
39
|
+
suggestion: "Some features (server-side user management, production auth) need a framework with a built-in server (Next.js, Astro, React Router v7). Skip this step or switch frameworks to enable it.",
|
|
40
|
+
retryable: false
|
|
41
|
+
},
|
|
42
|
+
ERR_ALREADY_APPLIED: {
|
|
43
|
+
humanMessage: "This is already set up in your project.",
|
|
44
|
+
suggestion: "Delete the existing files first if you want to re-create them, or skip this step.",
|
|
45
|
+
retryable: false
|
|
46
|
+
},
|
|
47
|
+
ERR_APPLY_UNSAFE_OVERWRITE: {
|
|
48
|
+
humanMessage: "One or more files already have your code in them.",
|
|
49
|
+
suggestion: "Retry with --force-overwrite to replace them, or edit the files manually first. Use --placement embed:<path> to write the chat entry file somewhere else entirely.",
|
|
50
|
+
retryable: true,
|
|
51
|
+
retryArgs: ["--force-overwrite"],
|
|
52
|
+
retryArgsLabel: "Overwrite and retry"
|
|
53
|
+
},
|
|
54
|
+
ERR_APPLY_ALREADY_APPLIED: {
|
|
55
|
+
humanMessage: "CometChat is already integrated in this project.",
|
|
56
|
+
suggestion: "If you want to re-apply (e.g., switching experience), retry with --force.",
|
|
57
|
+
retryable: true,
|
|
58
|
+
retryArgs: ["--force"],
|
|
59
|
+
retryArgsLabel: "Re-apply and override"
|
|
60
|
+
},
|
|
61
|
+
ERR_APP_CREATION_FAILED_MAX_LIMIT: {
|
|
62
|
+
humanMessage: "You've hit the free-tier app limit on this account.",
|
|
63
|
+
suggestion: "Delete an unused app from app.cometchat.com, then retry. Deleted apps count toward the limit for 30 days on some plans.",
|
|
64
|
+
retryable: false
|
|
65
|
+
},
|
|
66
|
+
ERR_APP_CREATION_FAILED: {
|
|
67
|
+
humanMessage: "The server couldn't create your app.",
|
|
68
|
+
suggestion: "Retry with a different name, or try a different region. If this keeps happening, contact support@cometchat.com.",
|
|
69
|
+
retryable: true
|
|
70
|
+
},
|
|
71
|
+
ERR_APP_NOT_FOUND: {
|
|
72
|
+
humanMessage: "The selected app doesn't exist on your account.",
|
|
73
|
+
suggestion: "Pick a different app from the list, or create a new one.",
|
|
74
|
+
retryable: false
|
|
75
|
+
},
|
|
76
|
+
ERR_ACCESS_DENIED: {
|
|
77
|
+
humanMessage: "You don't have permission to perform this action.",
|
|
78
|
+
suggestion: "If this is a team app, ask the owner to grant you access.",
|
|
79
|
+
retryable: false
|
|
80
|
+
},
|
|
81
|
+
ERR_BAD_REQUEST: {
|
|
82
|
+
humanMessage: "The server rejected the request as invalid.",
|
|
83
|
+
suggestion: "This usually means a field didn't pass validation. Double-check your inputs and retry.",
|
|
84
|
+
retryable: true
|
|
85
|
+
},
|
|
86
|
+
ERR_TOO_MANY_DIRECT_REQUESTS: {
|
|
87
|
+
humanMessage: "Too many requests \u2014 you've been rate-limited.",
|
|
88
|
+
suggestion: "Wait a minute and try again.",
|
|
89
|
+
retryable: true
|
|
90
|
+
},
|
|
91
|
+
NETWORK: {
|
|
92
|
+
humanMessage: "Couldn't reach the CometChat API.",
|
|
93
|
+
suggestion: "Check your internet connection. If you're behind a corporate proxy, make sure it allows traffic to apimgmt.cc-cluster-2.io.",
|
|
94
|
+
retryable: true
|
|
95
|
+
},
|
|
96
|
+
PARSE: {
|
|
97
|
+
humanMessage: "The CLI returned an unexpected response.",
|
|
98
|
+
suggestion: "This is likely a CLI bug. Re-run the last step; if it repeats, file an issue with the `--verbose` output.",
|
|
99
|
+
retryable: true
|
|
100
|
+
},
|
|
101
|
+
ERR_TOO_LARGE_FILE: {
|
|
102
|
+
humanMessage: "The file you tried to upload is too big.",
|
|
103
|
+
suggestion: "Reduce the file size or check your app's upload limits in the dashboard.",
|
|
104
|
+
retryable: true
|
|
105
|
+
},
|
|
106
|
+
ERR_MISSING_CUSTOMIZE_KEY: {
|
|
107
|
+
humanMessage: "No Claude API key found. Set ANTHROPIC_API_KEY to enable the `customize` command. A CometChat-hosted gateway is coming.",
|
|
108
|
+
suggestion: "Export ANTHROPIC_API_KEY in your shell (or a .env file) with a key from https://console.anthropic.com/, then re-run the command.",
|
|
109
|
+
retryable: false
|
|
110
|
+
},
|
|
111
|
+
ERR_CUSTOMIZE_NETWORK: {
|
|
112
|
+
humanMessage: "Couldn't reach the LLM endpoint.",
|
|
113
|
+
suggestion: "Check your connection and API key.",
|
|
114
|
+
retryable: true
|
|
115
|
+
},
|
|
116
|
+
ERR_CUSTOMIZE_API: {
|
|
117
|
+
humanMessage: "The LLM API returned an error.",
|
|
118
|
+
suggestion: "Re-check your API key and try again. If the error persists, the upstream provider may be degraded.",
|
|
119
|
+
retryable: true
|
|
120
|
+
},
|
|
121
|
+
ERR_CUSTOMIZE_UNSAFE_PATH: {
|
|
122
|
+
humanMessage: "The AI tried to modify a file it shouldn't.",
|
|
123
|
+
suggestion: "This is a safety check. Re-run with a more specific instruction.",
|
|
124
|
+
retryable: true
|
|
125
|
+
},
|
|
126
|
+
ERR_CUSTOMIZE_PATCH_TOO_LARGE: {
|
|
127
|
+
humanMessage: "The proposed change is too large to apply automatically.",
|
|
128
|
+
suggestion: "Break the request into smaller pieces.",
|
|
129
|
+
retryable: true
|
|
130
|
+
},
|
|
131
|
+
ERR_CUSTOMIZE_INVALID_ACTION: {
|
|
132
|
+
humanMessage: "The AI proposed an inconsistent change (e.g., create-over-existing).",
|
|
133
|
+
suggestion: "Re-run the command; the model may recover on retry.",
|
|
134
|
+
retryable: true
|
|
135
|
+
},
|
|
136
|
+
ERR_CUSTOMIZE_LOW_CONFIDENCE: {
|
|
137
|
+
humanMessage: "The AI isn't confident about this change.",
|
|
138
|
+
suggestion: "Review the plan and diff carefully before applying, or rephrase the instruction with more detail.",
|
|
139
|
+
retryable: true
|
|
140
|
+
}
|
|
141
|
+
};
|
|
142
|
+
function parseErrorCode(raw) {
|
|
143
|
+
if (!raw) return null;
|
|
144
|
+
const trimmed = raw.trim();
|
|
145
|
+
if (trimmed.length === 0) return null;
|
|
146
|
+
const apiMatch = trimmed.match(/^API_ERROR:\s*([A-Z0-9_]+)/);
|
|
147
|
+
if (apiMatch && apiMatch[1]) return apiMatch[1];
|
|
148
|
+
const bareMatch = trimmed.match(/^([A-Z][A-Z0-9_]*)(?:\s|$)/);
|
|
149
|
+
if (bareMatch && bareMatch[1] && bareMatch[1] === bareMatch[1].toUpperCase()) {
|
|
150
|
+
return bareMatch[1];
|
|
151
|
+
}
|
|
152
|
+
return null;
|
|
153
|
+
}
|
|
154
|
+
function explainError(input) {
|
|
155
|
+
const resolvedCode = (input.code && input.code.length > 0 ? input.code : null) ?? parseErrorCode(input.rawError);
|
|
156
|
+
if (resolvedCode && DICTIONARY[resolvedCode]) {
|
|
157
|
+
const entry = DICTIONARY[resolvedCode];
|
|
158
|
+
return { code: resolvedCode, ...entry };
|
|
159
|
+
}
|
|
160
|
+
return {
|
|
161
|
+
code: resolvedCode ?? "",
|
|
162
|
+
humanMessage: input.rawError,
|
|
163
|
+
suggestion: "",
|
|
164
|
+
retryable: true
|
|
165
|
+
};
|
|
166
|
+
}
|
|
167
|
+
export {
|
|
168
|
+
explainError,
|
|
169
|
+
parseErrorCode
|
|
170
|
+
};
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
const ROLES = [
|
|
2
|
+
{ key: "frontend", label: "Frontend Developer" },
|
|
3
|
+
{ key: "backend", label: "Backend Developer" },
|
|
4
|
+
{ key: "fullstack_engineer", label: "Fullstack Developer" },
|
|
5
|
+
{ key: "startup_founder", label: "Founder" },
|
|
6
|
+
{ key: "product_leader/manager", label: "Product Manager" },
|
|
7
|
+
{ key: "engineering_leader/manager", label: "Engineering Manager" },
|
|
8
|
+
{ key: "others", label: "Other" }
|
|
9
|
+
];
|
|
10
|
+
const ROLE_KEYS = ROLES.map((r) => r.key);
|
|
11
|
+
const INDUSTRIES = [
|
|
12
|
+
{ key: "online_marketplaces", label: "Online Marketplaces" },
|
|
13
|
+
{ key: "healthcare", label: "Healthcare" },
|
|
14
|
+
{ key: "dating", label: "Dating" },
|
|
15
|
+
{ key: "events_and_streaming", label: "Events & Streaming" },
|
|
16
|
+
{ key: "online_education", label: "Online Education" },
|
|
17
|
+
{ key: "community_and_social", label: "Community & Social" },
|
|
18
|
+
{ key: "saas_businesses", label: "SaaS & Multi-Tenant" },
|
|
19
|
+
{ key: "sports_and_gaming", label: "Sports & Gaming" },
|
|
20
|
+
{ key: "team_comms_and_workflows", label: "Team Comms & Workflows" },
|
|
21
|
+
{ key: "on_demand_services", label: "On-Demand Services" },
|
|
22
|
+
{ key: "other", label: "Other" }
|
|
23
|
+
];
|
|
24
|
+
const INDUSTRY_KEYS = INDUSTRIES.map((i) => i.key);
|
|
25
|
+
export {
|
|
26
|
+
INDUSTRIES,
|
|
27
|
+
INDUSTRY_KEYS,
|
|
28
|
+
ROLES,
|
|
29
|
+
ROLE_KEYS
|
|
30
|
+
};
|
package/package.json
CHANGED
|
@@ -1,12 +1,19 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@cometchat/skills-cli",
|
|
3
|
-
"version": "2.0
|
|
4
|
-
"description": "CLI for the CometChat skills
|
|
3
|
+
"version": "2.1.0",
|
|
4
|
+
"description": "CLI for the CometChat skills v3 architecture — auth, provision, detect, apply, verify CometChat integrations in React/Next.js/React-Router/Astro projects.",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"license": "MIT",
|
|
7
7
|
"bin": {
|
|
8
8
|
"cometchat": "bin/cometchat.mjs"
|
|
9
9
|
},
|
|
10
|
+
"exports": {
|
|
11
|
+
".": "./dist/index.js",
|
|
12
|
+
"./bin/cometchat.mjs": "./bin/cometchat.mjs",
|
|
13
|
+
"./onboarding-options": "./dist/utils/onboarding-options.js",
|
|
14
|
+
"./error-dictionary": "./dist/utils/error-dictionary.js",
|
|
15
|
+
"./package.json": "./package.json"
|
|
16
|
+
},
|
|
10
17
|
"files": [
|
|
11
18
|
"bin/",
|
|
12
19
|
"dist/",
|
|
@@ -16,7 +23,7 @@
|
|
|
16
23
|
"dev": "tsx src/index.ts",
|
|
17
24
|
"test": "node --test --import tsx test/*.test.ts",
|
|
18
25
|
"test:watch": "node --test --watch --import tsx test/*.test.ts",
|
|
19
|
-
"build": "rm -rf dist && esbuild src/index.ts --bundle --platform=node --format=esm --outfile=dist/index.js --packages=external && node -e \"require('node:fs').cpSync(require('node:path').resolve('../registry/v6'),require('node:path').resolve('dist/registry/v6'),{recursive:true});require('node:fs').cpSync(require('node:path').resolve('../registry/schemas'),require('node:path').resolve('dist/registry/schemas'),{recursive:true});console.log(' bundled registry → dist/registry/');\"",
|
|
26
|
+
"build": "rm -rf dist && esbuild src/index.ts --bundle --platform=node --format=esm --outfile=dist/index.js --packages=external && esbuild src/utils/onboarding-options.ts --platform=node --format=esm --outfile=dist/utils/onboarding-options.js && esbuild src/utils/error-dictionary.ts --platform=node --format=esm --outfile=dist/utils/error-dictionary.js && node -e \"require('node:fs').cpSync(require('node:path').resolve('../registry/v6'),require('node:path').resolve('dist/registry/v6'),{recursive:true});require('node:fs').cpSync(require('node:path').resolve('../registry/schemas'),require('node:path').resolve('dist/registry/schemas'),{recursive:true});console.log(' bundled registry → dist/registry/');\"",
|
|
20
27
|
"typecheck": "tsc --noEmit",
|
|
21
28
|
"prepublishOnly": "npm run typecheck && npm test && npm run build"
|
|
22
29
|
},
|
|
@@ -25,7 +32,7 @@
|
|
|
25
32
|
},
|
|
26
33
|
"devDependencies": {
|
|
27
34
|
"@types/node": "^20.0.0",
|
|
28
|
-
"esbuild": "^0.
|
|
35
|
+
"esbuild": "^0.25.0",
|
|
29
36
|
"tsx": "^4.19.0",
|
|
30
37
|
"typescript": "^5.6.0"
|
|
31
38
|
},
|