@cometchat/skills-cli 2.0.4 → 2.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.
Files changed (25) hide show
  1. package/LICENSE +21 -0
  2. package/bin/cometchat.mjs +12 -6
  3. package/dist/index.js +5512 -515
  4. package/dist/registry/schemas/config.schema.json +119 -0
  5. package/dist/registry/v6/experiences/1-conversation-list/reactjs-dedicated-route.template.json +81 -0
  6. package/dist/registry/v6/experiences/1-conversation-list/templates/reactjs-dedicated-route/ChatPage.tsx.tpl +87 -0
  7. package/dist/registry/v6/experiences/1-conversation-list/templates/reactjs-dedicated-route/CometChatMessenger.css.tpl +20 -0
  8. package/dist/registry/v6/experiences/1-conversation-list/templates/reactjs-dedicated-route/CometChatMessenger.tsx.tpl +54 -0
  9. package/dist/registry/v6/experiences/1-conversation-list/templates/reactjs-dedicated-route/CometChatSelector.tsx.tpl +40 -0
  10. package/dist/registry/v6/experiences/2-one-to-one/reactjs-dedicated-route.template.json +75 -0
  11. package/dist/registry/v6/experiences/2-one-to-one/reactjs.template.json +6 -3
  12. package/dist/registry/v6/experiences/2-one-to-one/templates/reactjs-dedicated-route/ChatPage.tsx.tpl +84 -0
  13. package/dist/registry/v6/experiences/2-one-to-one/templates/reactjs-dedicated-route/CometChatMessenger.css.tpl +9 -0
  14. package/dist/registry/v6/experiences/2-one-to-one/templates/reactjs-dedicated-route/CometChatMessenger.tsx.tpl +43 -0
  15. package/dist/registry/v6/experiences/3-tab-based/reactjs-dedicated-route.template.json +89 -0
  16. package/dist/registry/v6/experiences/3-tab-based/reactjs.template.json +6 -3
  17. package/dist/registry/v6/experiences/3-tab-based/templates/reactjs-dedicated-route/ChatPage.tsx.tpl +84 -0
  18. package/dist/registry/v6/experiences/3-tab-based/templates/reactjs-dedicated-route/CometChatMessenger.css.tpl +11 -0
  19. package/dist/registry/v6/experiences/3-tab-based/templates/reactjs-dedicated-route/CometChatMessenger.tsx.tpl +61 -0
  20. package/dist/registry/v6/experiences/3-tab-based/templates/reactjs-dedicated-route/CometChatTabs.css.tpl +43 -0
  21. package/dist/registry/v6/experiences/3-tab-based/templates/reactjs-dedicated-route/CometChatTabs.tsx.tpl +72 -0
  22. package/dist/registry/v6/features/catalog.json +9 -1
  23. package/dist/utils/error-dictionary.js +170 -0
  24. package/dist/utils/onboarding-options.js +30 -0
  25. 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",
@@ -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
+ };
@@ -326,8 +326,16 @@
326
326
  "id": "calls",
327
327
  "name": "Audio/Video Calls",
328
328
  "type": "package-install",
329
- "description": "1:1 and group audio/video calling. Includes call buttons in headers, incoming/outgoing call UI, and call logs. Requires installing @cometchat/calls-sdk-javascript.",
329
+ "description": "1:1 and group audio/video calling. Includes call buttons in headers, incoming/outgoing call UI, and call logs. Requires installing the calls SDK for your platform.",
330
330
  "package": "@cometchat/calls-sdk-javascript",
331
+ "package_native": "@cometchat/calls-sdk-react-native",
332
+ "package_native_peers": [
333
+ "react-native-webrtc",
334
+ "react-native-incall-manager",
335
+ "react-native-background-timer",
336
+ "react-native-callstats",
337
+ "@react-native-community/netinfo"
338
+ ],
331
339
  "components": ["CometChatIncomingCall", "CometChatOutgoingCall", "CometChatCallLogs"],
332
340
  "docs_topic": "call-features"
333
341
  },
@@ -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",
4
- "description": "CLI for the CometChat skills v2 architecture — detect, view, apply, verify CometChat integrations in React projects.",
3
+ "version": "2.2.0",
4
+ "description": "CLI for the CometChat skills v3 architecture — auth, provision, detect, apply, verify CometChat integrations in React/Next.js/React-Router/Astro/Expo/React-Native 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.24.0",
35
+ "esbuild": "^0.25.0",
29
36
  "tsx": "^4.19.0",
30
37
  "typescript": "^5.6.0"
31
38
  },