@cometchat/skills 3.1.0 → 4.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/README.md +75 -17
- package/bin/install.js +523 -43
- package/package.json +17 -8
- package/skills/cometchat/SKILL.md +850 -109
- package/skills/cometchat-android-v5/SKILL.md +120 -0
- package/skills/cometchat-android-v5-components/SKILL.md +430 -0
- package/skills/cometchat-android-v5-core/SKILL.md +468 -0
- package/skills/cometchat-android-v5-customization/SKILL.md +305 -0
- package/skills/cometchat-android-v5-extensions/SKILL.md +124 -0
- package/skills/cometchat-android-v5-features/SKILL.md +130 -0
- package/skills/cometchat-android-v5-placement/SKILL.md +276 -0
- package/skills/cometchat-android-v5-production/SKILL.md +94 -0
- package/skills/cometchat-android-v5-push/SKILL.md +620 -0
- package/skills/cometchat-android-v5-testing/SKILL.md +187 -0
- package/skills/cometchat-android-v5-theming/SKILL.md +166 -0
- package/skills/cometchat-android-v5-troubleshooting/SKILL.md +73 -0
- package/skills/cometchat-android-v6/SKILL.md +107 -0
- package/skills/cometchat-android-v6-builder-settings/SKILL.md +145 -0
- package/skills/cometchat-android-v6-compose-components/SKILL.md +202 -0
- package/skills/cometchat-android-v6-compose-customization/SKILL.md +280 -0
- package/skills/cometchat-android-v6-compose-placement/SKILL.md +213 -0
- package/skills/cometchat-android-v6-compose-theming/SKILL.md +224 -0
- package/skills/cometchat-android-v6-core/SKILL.md +354 -0
- package/skills/cometchat-android-v6-events/SKILL.md +212 -0
- package/skills/cometchat-android-v6-extensions/SKILL.md +191 -0
- package/skills/cometchat-android-v6-features/SKILL.md +130 -0
- package/skills/cometchat-android-v6-kotlin-components/SKILL.md +197 -0
- package/skills/cometchat-android-v6-kotlin-customization/SKILL.md +268 -0
- package/skills/cometchat-android-v6-kotlin-placement/SKILL.md +248 -0
- package/skills/cometchat-android-v6-kotlin-theming/SKILL.md +202 -0
- package/skills/cometchat-android-v6-production/SKILL.md +187 -0
- package/skills/cometchat-android-v6-push/SKILL.md +274 -0
- package/skills/cometchat-android-v6-testing/SKILL.md +279 -0
- package/skills/cometchat-android-v6-troubleshooting/SKILL.md +249 -0
- package/skills/cometchat-angular-components/SKILL.md +706 -0
- package/skills/cometchat-angular-core/SKILL.md +444 -0
- package/skills/cometchat-angular-customization/SKILL.md +424 -0
- package/skills/cometchat-angular-features/SKILL.md +447 -0
- package/skills/cometchat-angular-patterns/SKILL.md +447 -0
- package/skills/cometchat-angular-placement/SKILL.md +685 -0
- package/skills/cometchat-angular-production/SKILL.md +415 -0
- package/skills/cometchat-angular-theming/SKILL.md +365 -0
- package/skills/cometchat-angular-troubleshooting/SKILL.md +329 -0
- package/skills/cometchat-astro-patterns/SKILL.md +3 -3
- package/skills/cometchat-components/SKILL.md +2 -0
- package/skills/cometchat-core/SKILL.md +11 -6
- package/skills/cometchat-customization/references/component-catalog.md +1 -1
- package/skills/cometchat-features/SKILL.md +176 -108
- package/skills/cometchat-flutter-v5/SKILL.md +167 -0
- package/skills/cometchat-flutter-v5-calls/SKILL.md +192 -0
- package/skills/cometchat-flutter-v5-conversations/SKILL.md +117 -0
- package/skills/cometchat-flutter-v5-core/SKILL.md +221 -0
- package/skills/cometchat-flutter-v5-customization/SKILL.md +227 -0
- package/skills/cometchat-flutter-v5-events/SKILL.md +155 -0
- package/skills/cometchat-flutter-v5-messages/SKILL.md +258 -0
- package/skills/cometchat-flutter-v5-production/SKILL.md +207 -0
- package/skills/cometchat-flutter-v5-push/SKILL.md +284 -0
- package/skills/cometchat-flutter-v5-theming/SKILL.md +160 -0
- package/skills/cometchat-flutter-v5-troubleshooting/SKILL.md +129 -0
- package/skills/cometchat-flutter-v5-users-groups/SKILL.md +151 -0
- package/skills/cometchat-flutter-v6/SKILL.md +445 -0
- package/skills/cometchat-flutter-v6-calls/SKILL.md +333 -0
- package/skills/cometchat-flutter-v6-components/SKILL.md +365 -0
- package/skills/cometchat-flutter-v6-conversations/SKILL.md +210 -0
- package/skills/cometchat-flutter-v6-core/SKILL.md +305 -0
- package/skills/cometchat-flutter-v6-customization/SKILL.md +666 -0
- package/skills/cometchat-flutter-v6-events/SKILL.md +216 -0
- package/skills/cometchat-flutter-v6-features/SKILL.md +406 -0
- package/skills/cometchat-flutter-v6-messages/SKILL.md +333 -0
- package/skills/cometchat-flutter-v6-migration/SKILL.md +381 -0
- package/skills/cometchat-flutter-v6-placement/SKILL.md +398 -0
- package/skills/cometchat-flutter-v6-production/SKILL.md +632 -0
- package/skills/cometchat-flutter-v6-theming/SKILL.md +260 -0
- package/skills/cometchat-flutter-v6-troubleshooting/SKILL.md +726 -0
- package/skills/cometchat-flutter-v6-users-groups/SKILL.md +216 -0
- package/skills/cometchat-ios/SKILL.md +323 -0
- package/skills/cometchat-ios-components/SKILL.md +651 -0
- package/skills/cometchat-ios-core/SKILL.md +822 -0
- package/skills/cometchat-ios-customization/SKILL.md +825 -0
- package/skills/cometchat-ios-features/SKILL.md +725 -0
- package/skills/cometchat-ios-placement/SKILL.md +750 -0
- package/skills/cometchat-ios-production/SKILL.md +730 -0
- package/skills/cometchat-ios-push/SKILL.md +582 -0
- package/skills/cometchat-ios-theming/SKILL.md +631 -0
- package/skills/cometchat-ios-troubleshooting/SKILL.md +983 -0
- package/skills/cometchat-native-bare-patterns/SKILL.md +470 -0
- package/skills/cometchat-native-components/SKILL.md +594 -0
- package/skills/cometchat-native-core/SKILL.md +407 -0
- package/skills/cometchat-native-customization/SKILL.md +594 -0
- package/skills/cometchat-native-expo-patterns/SKILL.md +485 -0
- package/skills/cometchat-native-features/SKILL.md +608 -0
- package/skills/cometchat-native-placement/SKILL.md +500 -0
- package/skills/cometchat-native-production/SKILL.md +694 -0
- package/skills/cometchat-native-push/SKILL.md +593 -0
- package/skills/cometchat-native-testing/SKILL.md +583 -0
- package/skills/cometchat-native-theming/SKILL.md +656 -0
- package/skills/cometchat-native-troubleshooting/SKILL.md +433 -0
- package/skills/cometchat-nextjs-patterns/SKILL.md +5 -5
- package/skills/cometchat-placement/SKILL.md +28 -0
- package/skills/cometchat-react-patterns/SKILL.md +55 -7
- package/skills/cometchat-react-router-patterns/SKILL.md +23 -21
package/bin/install.js
CHANGED
|
@@ -5,6 +5,8 @@
|
|
|
5
5
|
const fs = require("fs");
|
|
6
6
|
const path = require("path");
|
|
7
7
|
const os = require("os");
|
|
8
|
+
const readline = require("readline");
|
|
9
|
+
const { spawn } = require("child_process");
|
|
8
10
|
|
|
9
11
|
// ── Lazy-load optional deps ───────────────────────────────────────────────────
|
|
10
12
|
function tryRequire(name) {
|
|
@@ -27,25 +29,178 @@ const c = {
|
|
|
27
29
|
// ── Skills registry ───────────────────────────────────────────────────────────
|
|
28
30
|
const SKILLS_SRC_DIR = path.join(__dirname, "..", "skills");
|
|
29
31
|
|
|
32
|
+
// Each skill declares which families it belongs to. The dispatcher (`cometchat`)
|
|
33
|
+
// is shared across all families; pattern skills are family-specific. Adding a
|
|
34
|
+
// new family (e.g. flutter) means flipping its `coming soon` placeholder below
|
|
35
|
+
// to real entries with `families: ["flutter"]`.
|
|
30
36
|
const SKILLS = [
|
|
31
|
-
//
|
|
32
|
-
{ name: "cometchat",
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
{ name: "cometchat-
|
|
36
|
-
|
|
37
|
-
{ name: "cometchat-
|
|
38
|
-
{ name: "cometchat-
|
|
39
|
-
{ name: "cometchat-
|
|
40
|
-
{ name: "cometchat-
|
|
41
|
-
|
|
42
|
-
{ name: "cometchat-theming",
|
|
43
|
-
{ name: "cometchat-features",
|
|
44
|
-
{ name: "cometchat-customization",
|
|
45
|
-
{ name: "cometchat-production",
|
|
46
|
-
{ name: "cometchat-troubleshooting", description: "Diagnostics — verify, drift, doctor, symptom lookup" },
|
|
37
|
+
// Dispatcher — shared across every family
|
|
38
|
+
{ name: "cometchat", families: ["web", "native", "flutter", "angular", "android", "ios"], description: "Entry point — detects framework, handles onboarding, guides integration" },
|
|
39
|
+
|
|
40
|
+
// Web (React / Next.js / React Router / Astro)
|
|
41
|
+
{ name: "cometchat-core", families: ["web"], description: "Foundational rules — init, login, CSS, env vars, SSR safety, provider" },
|
|
42
|
+
{ name: "cometchat-components", families: ["web"], description: "Component catalog — names, props, composition patterns" },
|
|
43
|
+
{ name: "cometchat-placement", families: ["web"], description: "Where to put chat — route, modal, drawer, widget, embedded" },
|
|
44
|
+
{ name: "cometchat-react-patterns", families: ["web"], description: "React / Vite / CRA integration patterns" },
|
|
45
|
+
{ name: "cometchat-nextjs-patterns", families: ["web"], description: "Next.js App Router + Pages Router patterns" },
|
|
46
|
+
{ name: "cometchat-react-router-patterns", families: ["web"], description: "React Router v6 / v7 patterns" },
|
|
47
|
+
{ name: "cometchat-astro-patterns", families: ["web"], description: "Astro React islands patterns" },
|
|
48
|
+
{ name: "cometchat-theming", families: ["web"], description: "Theme presets, brand colors, CSS variable overrides" },
|
|
49
|
+
{ name: "cometchat-features", families: ["web"], description: "40+ feature catalog — calls, polls, AI, moderation" },
|
|
50
|
+
{ name: "cometchat-customization", families: ["web"], description: "Component customization — custom views, builders, events" },
|
|
51
|
+
{ name: "cometchat-production", families: ["web"], description: "Production auth — token endpoints, user management, security" },
|
|
52
|
+
{ name: "cometchat-troubleshooting", families: ["web"], description: "Diagnostics — verify, drift, doctor, symptom lookup" },
|
|
53
|
+
|
|
54
|
+
// React Native (Expo + bare RN)
|
|
55
|
+
{ name: "cometchat-native-core", families: ["native"], description: "RN: init, login, provider chain, env vars, anti-patterns" },
|
|
56
|
+
{ name: "cometchat-native-components", families: ["native"], description: "RN component catalog — names, props, slot views, request builders" },
|
|
57
|
+
{ name: "cometchat-native-placement", families: ["native"], description: "RN: stack screen, bottom tab, modal, bottom sheet, embedded" },
|
|
58
|
+
{ name: "cometchat-native-expo-patterns", families: ["native"], description: "Expo managed workflow + Expo Router + app.json config" },
|
|
59
|
+
{ name: "cometchat-native-bare-patterns", families: ["native"], description: "Bare RN: pod install, native modules, privacy manifest" },
|
|
60
|
+
{ name: "cometchat-native-theming", families: ["native"], description: "RN: CometChatThemeProvider — colors, typography, dark mode" },
|
|
61
|
+
{ name: "cometchat-native-features", families: ["native"], description: "RN feature catalog — calls, extensions, AI agent, reactions, polls" },
|
|
62
|
+
{ name: "cometchat-native-customization", families: ["native"], description: "RN: custom text formatters, events, request builder filtering" },
|
|
63
|
+
{ name: "cometchat-native-production", families: ["native"], description: "RN: server-minted auth tokens, user management, external-backend recipes" },
|
|
64
|
+
{ name: "cometchat-native-push", families: ["native"], description: "RN push: APNs + FCM, dashboard providers, client registration, deep-link" },
|
|
65
|
+
{ name: "cometchat-native-testing", families: ["native"], description: "RN testing: Jest + RNTL, mocking the kit/SDK, Detox vs Maestro, CI" },
|
|
66
|
+
{ name: "cometchat-native-troubleshooting", families: ["native"], description: "RN troubleshooting: Metro cache, pod install, native module linking" },
|
|
67
|
+
|
|
68
|
+
// Angular (12-15)
|
|
69
|
+
{ name: "cometchat-angular-core", families: ["angular"], description: "Angular: UIKitSettingsBuilder init, login order, environment config, provider" },
|
|
70
|
+
{ name: "cometchat-angular-components", families: ["angular"], description: "Angular component catalog — selectors, inputs, content projection, modules" },
|
|
71
|
+
{ name: "cometchat-angular-placement", families: ["angular"], description: "Angular: route, modal, drawer, embedded panel — where to put chat" },
|
|
72
|
+
{ name: "cometchat-angular-patterns", families: ["angular"], description: "Angular integration patterns — modules, lazy loading, environment files" },
|
|
73
|
+
{ name: "cometchat-angular-theming", families: ["angular"], description: "Angular: CometChatThemeService — colors, typography, dark mode" },
|
|
74
|
+
{ name: "cometchat-angular-features", families: ["angular"], description: "Angular feature catalog — calls, polls, reactions, extensions, AI" },
|
|
75
|
+
{ name: "cometchat-angular-customization", families: ["angular"], description: "Angular: content projection, ng-template slots, custom views" },
|
|
76
|
+
{ name: "cometchat-angular-production", families: ["angular"], description: "Angular: server-minted auth tokens, user management, external-backend recipes" },
|
|
77
|
+
{ name: "cometchat-angular-troubleshooting", families: ["angular"], description: "Angular troubleshooting: build errors, module imports, Zone.js issues" },
|
|
78
|
+
|
|
79
|
+
// Android native — both V5 (live, Java + Kotlin Views) and V6 (beta,
|
|
80
|
+
// Compose + Kotlin Views) ship together. The V5 + V6 dispatcher entries
|
|
81
|
+
// (`cometchat-android-v5` / `cometchat-android-v6`) are routed by the
|
|
82
|
+
// unified `cometchat` dispatcher after detecting the gradle dep.
|
|
83
|
+
{ name: "cometchat-android-v5", families: ["android"], description: "V5 dispatcher — Java + Kotlin Views (com.cometchat:chat-uikit-android:5.x)" },
|
|
84
|
+
{ name: "cometchat-android-v5-core", families: ["android"], description: "V5: UIKitSettings init, login, dependency setup" },
|
|
85
|
+
{ name: "cometchat-android-v5-components", families: ["android"], description: "V5 component catalog — Conversations, Messages, Users, Groups, Calls" },
|
|
86
|
+
{ name: "cometchat-android-v5-placement", families: ["android"], description: "V5: Activity, Fragment, BottomSheet — where to put chat" },
|
|
87
|
+
{ name: "cometchat-android-v5-theming", families: ["android"], description: "V5: theme attrs, colors.xml, dark mode, brand styling" },
|
|
88
|
+
{ name: "cometchat-android-v5-features", families: ["android"], description: "V5 feature catalog — calls, reactions, polls, extensions, AI" },
|
|
89
|
+
{ name: "cometchat-android-v5-customization", families: ["android"], description: "V5: custom views, DataSource decorators, request builders" },
|
|
90
|
+
{ name: "cometchat-android-v5-production", families: ["android"], description: "V5: server-minted auth tokens, user management, external-backend recipes" },
|
|
91
|
+
{ name: "cometchat-android-v5-push", families: ["android"], description: "V5 push: FCM, dashboard providers, deep-link, foreground/background" },
|
|
92
|
+
{ name: "cometchat-android-v5-extensions", families: ["android"], description: "V5 extensions — moderation, smart replies, message translation" },
|
|
93
|
+
{ name: "cometchat-android-v5-testing", families: ["android"], description: "V5 testing: Espresso, Robolectric, mocking the kit/SDK" },
|
|
94
|
+
{ name: "cometchat-android-v5-troubleshooting", families: ["android"], description: "V5 troubleshooting: gradle conflicts, manifest, lifecycle, ProGuard" },
|
|
95
|
+
|
|
96
|
+
{ name: "cometchat-android-v6", families: ["android"], description: "V6 dispatcher — Compose + Kotlin Views (chatuikit-{compose,kotlin}-android:6.x)" },
|
|
97
|
+
{ name: "cometchat-android-v6-core", families: ["android"], description: "V6: gradle deps, init, login, message sending" },
|
|
98
|
+
{ name: "cometchat-android-v6-events", families: ["android"], description: "V6: SDK event subscriptions and lifecycle" },
|
|
99
|
+
{ name: "cometchat-android-v6-compose-components", families: ["android"], description: "V6 Compose component catalog — Composables for chat UI" },
|
|
100
|
+
{ name: "cometchat-android-v6-compose-placement", families: ["android"], description: "V6 Compose: NavHost, modal, bottom sheet — where to put chat" },
|
|
101
|
+
{ name: "cometchat-android-v6-compose-theming", families: ["android"], description: "V6 Compose: CometChatTheme, color schemes, typography" },
|
|
102
|
+
{ name: "cometchat-android-v6-compose-customization", families: ["android"], description: "V6 Compose: custom slots, DataSource, message templates" },
|
|
103
|
+
{ name: "cometchat-android-v6-kotlin-components", families: ["android"], description: "V6 Kotlin Views component catalog — custom View classes" },
|
|
104
|
+
{ name: "cometchat-android-v6-kotlin-placement", families: ["android"], description: "V6 Kotlin Views: Activity, Fragment, BottomSheet placement" },
|
|
105
|
+
{ name: "cometchat-android-v6-kotlin-theming", families: ["android"], description: "V6 Kotlin Views: style attributes, colors.xml, dark mode" },
|
|
106
|
+
{ name: "cometchat-android-v6-kotlin-customization", families: ["android"], description: "V6 Kotlin Views: custom Views, DataSource, request builders" },
|
|
107
|
+
{ name: "cometchat-android-v6-features", families: ["android"], description: "V6 feature catalog — calls, reactions, polls, AI agent, extensions" },
|
|
108
|
+
{ name: "cometchat-android-v6-extensions", families: ["android"], description: "V6 extensions — moderation, smart replies, message translation" },
|
|
109
|
+
{ name: "cometchat-android-v6-builder-settings", families: ["android"], description: "V6: UIKitSettingsBuilder options — presence, typing, receipts" },
|
|
110
|
+
{ name: "cometchat-android-v6-production", families: ["android"], description: "V6: server-minted auth tokens, user management, external-backend recipes" },
|
|
111
|
+
{ name: "cometchat-android-v6-push", families: ["android"], description: "V6 push: FCM, dashboard providers, deep-link" },
|
|
112
|
+
{ name: "cometchat-android-v6-testing", families: ["android"], description: "V6 testing: Espresso, Robolectric, Compose UI tests, mocking" },
|
|
113
|
+
{ name: "cometchat-android-v6-troubleshooting", families: ["android"], description: "V6 troubleshooting: gradle, Compose runtime, R8, BuildConfig" },
|
|
114
|
+
|
|
115
|
+
// Flutter — V5 stable (`cometchat_chat_uikit:^5.2`) + V6 beta
|
|
116
|
+
// (`cometchat_chat_uikit:^6.0.0-beta`) ship together. Routed by the
|
|
117
|
+
// unified `cometchat` dispatcher after detecting the pubspec.yaml dep.
|
|
118
|
+
{ name: "cometchat-flutter-v5", families: ["flutter"], description: "V5 dispatcher — cometchat_chat_uikit ^5.2 + cometchat_calls_uikit ^5.0" },
|
|
119
|
+
{ name: "cometchat-flutter-v5-core", families: ["flutter"], description: "V5: pubspec deps, UIKitSettings, init/login, app entry" },
|
|
120
|
+
{ name: "cometchat-flutter-v5-conversations", families: ["flutter"], description: "V5: CometChatConversations widget — props, callbacks, request builder" },
|
|
121
|
+
{ name: "cometchat-flutter-v5-messages", families: ["flutter"], description: "V5: CometChatMessages screen — message list, header, composer wiring" },
|
|
122
|
+
{ name: "cometchat-flutter-v5-users-groups", families: ["flutter"], description: "V5: CometChatUsers / CometChatGroups / CometChatGroupMembers" },
|
|
123
|
+
{ name: "cometchat-flutter-v5-calls", families: ["flutter"], description: "V5: voice/video calling — incoming/outgoing/ongoing screens, call buttons" },
|
|
124
|
+
{ name: "cometchat-flutter-v5-theming", families: ["flutter"], description: "V5: CometChatTheme, color palette, typography, dark mode" },
|
|
125
|
+
{ name: "cometchat-flutter-v5-customization", families: ["flutter"], description: "V5: custom message templates, options, text formatters, builders" },
|
|
126
|
+
{ name: "cometchat-flutter-v5-events", families: ["flutter"], description: "V5: CometChatMessageEvents / GroupEvents / CallEvents subscription" },
|
|
127
|
+
{ name: "cometchat-flutter-v5-production", families: ["flutter"], description: "V5: server-minted auth tokens, user management, external-backend recipes" },
|
|
128
|
+
{ name: "cometchat-flutter-v5-push", families: ["flutter"], description: "V5: FCM/APNs push, token lifecycle, deep-link" },
|
|
129
|
+
{ name: "cometchat-flutter-v5-troubleshooting", families: ["flutter"], description: "V5 troubleshooting: pubspec, GetX, Pod errors, runtime crashes" },
|
|
130
|
+
|
|
131
|
+
{ name: "cometchat-flutter-v6", families: ["flutter"], description: "V6 dispatcher — cometchat_chat_uikit ^6.0.0-beta (Bloc-based)" },
|
|
132
|
+
{ name: "cometchat-flutter-v6-core", families: ["flutter"], description: "V6: pubspec deps, UIKitSettings, init/login, app entry" },
|
|
133
|
+
{ name: "cometchat-flutter-v6-components", families: ["flutter"], description: "V6 component catalog — Bloc-driven widgets, slots, request builders" },
|
|
134
|
+
{ name: "cometchat-flutter-v6-conversations", families: ["flutter"], description: "V6: CometChatConversations widget — Bloc, request builder, callbacks" },
|
|
135
|
+
{ name: "cometchat-flutter-v6-messages", families: ["flutter"], description: "V6: CometChatMessages — list / header / composer composition" },
|
|
136
|
+
{ name: "cometchat-flutter-v6-users-groups", families: ["flutter"], description: "V6: CometChatUsers / CometChatGroups / CometChatGroupMembers" },
|
|
137
|
+
{ name: "cometchat-flutter-v6-calls", families: ["flutter"], description: "V6: voice/video calling — incoming/outgoing/ongoing screens" },
|
|
138
|
+
{ name: "cometchat-flutter-v6-features", families: ["flutter"], description: "V6 feature catalog — calls, polls, reactions, AI, extensions" },
|
|
139
|
+
{ name: "cometchat-flutter-v6-placement", families: ["flutter"], description: "V6: route, modal sheet, embedded widget — where chat lives in the app" },
|
|
140
|
+
{ name: "cometchat-flutter-v6-theming", families: ["flutter"], description: "V6: CometChatThemeHelper, CometChatColorPalette, light/dark schemes" },
|
|
141
|
+
{ name: "cometchat-flutter-v6-customization", families: ["flutter"], description: "V6: bubble factories, message templates, text formatters, slot widgets" },
|
|
142
|
+
{ name: "cometchat-flutter-v6-events", families: ["flutter"], description: "V6: Bloc-based event streams + listener registration" },
|
|
143
|
+
{ name: "cometchat-flutter-v6-production", families: ["flutter"], description: "V6: server-minted auth tokens, user management, external-backend recipes" },
|
|
144
|
+
{ name: "cometchat-flutter-v6-troubleshooting", families: ["flutter"], description: "V6 troubleshooting: pubspec, Bloc, theme cache, build errors" },
|
|
145
|
+
{ name: "cometchat-flutter-v6-migration", families: ["flutter"], description: "V5→V6 migration recipes — GetX → Bloc, theme API rewrite, breaking changes" },
|
|
146
|
+
|
|
147
|
+
// iOS — V5 stable (`CometChatUIKitSwift:^5`). No V6 beta yet; when
|
|
148
|
+
// it ships, add per-cohort namespacing as Android/Flutter do today.
|
|
149
|
+
{ name: "cometchat-ios", families: ["ios"], description: "iOS dispatcher — Swift project setup, dependency manager routing" },
|
|
150
|
+
{ name: "cometchat-ios-core", families: ["ios"], description: "iOS: SDK init, login, UIKit settings builder, SwiftUI/UIKit entry points" },
|
|
151
|
+
{ name: "cometchat-ios-components", families: ["ios"], description: "iOS component catalog — view controllers, SwiftUI views, request builders" },
|
|
152
|
+
{ name: "cometchat-ios-placement", families: ["ios"], description: "iOS: navigation controller, modal, tab, embedded — where chat lives" },
|
|
153
|
+
{ name: "cometchat-ios-theming", families: ["ios"], description: "iOS: CometChatTheme, color tokens, typography, dark mode" },
|
|
154
|
+
{ name: "cometchat-ios-features", families: ["ios"], description: "iOS feature catalog — calls, polls, reactions, AI, extensions" },
|
|
155
|
+
{ name: "cometchat-ios-customization", families: ["ios"], description: "iOS: custom views, message templates, text formatters, DataSource decorators" },
|
|
156
|
+
{ name: "cometchat-ios-production", families: ["ios"], description: "iOS: server-minted auth tokens, user management, external-backend recipes" },
|
|
157
|
+
{ name: "cometchat-ios-push", families: ["ios"], description: "iOS push: APNs + VoIP, CallKit, token lifecycle, deep-link" },
|
|
158
|
+
{ name: "cometchat-ios-troubleshooting", families: ["ios"], description: "iOS troubleshooting: SPM, CocoaPods, Xcode build errors, Info.plist, runtime crashes" },
|
|
47
159
|
];
|
|
48
160
|
|
|
161
|
+
// ── Base skills (cross-family) ────────────────────────────────────────────────
|
|
162
|
+
//
|
|
163
|
+
// Skills registered for ALL six families. These are the baseline a dispatcher
|
|
164
|
+
// needs to detect framework and route — they're installed in the default
|
|
165
|
+
// interactive flow, before any family is resolved. The dispatcher (read at
|
|
166
|
+
// runtime in the user's IDE) detects the framework and asks the agent to
|
|
167
|
+
// install the relevant family skills via:
|
|
168
|
+
//
|
|
169
|
+
// npx @cometchat/skills add --family <X> --ide <Y>
|
|
170
|
+
//
|
|
171
|
+
// (Logic already in `skills/cometchat/SKILL.md` Step 1 — "If `framework` is
|
|
172
|
+
// X AND `cometchat-{X}-core` is NOT loaded: <install command>".)
|
|
173
|
+
//
|
|
174
|
+
// This list grows automatically as more cross-family skills are registered
|
|
175
|
+
// (e.g. when the calls work merges, cometchat-calls/i18n/a11y join).
|
|
176
|
+
const ALL_FAMILIES_SET = ["web", "native", "flutter", "angular", "android", "ios"];
|
|
177
|
+
const BASE_SKILLS = SKILLS.filter(s =>
|
|
178
|
+
ALL_FAMILIES_SET.every(f => s.families.includes(f))
|
|
179
|
+
);
|
|
180
|
+
|
|
181
|
+
// ── Framework → family routing ────────────────────────────────────────────────
|
|
182
|
+
const FRAMEWORK_TO_FAMILY = {
|
|
183
|
+
reactjs: "web",
|
|
184
|
+
nextjs: "web",
|
|
185
|
+
"react-router": "web",
|
|
186
|
+
astro: "web",
|
|
187
|
+
expo: "native",
|
|
188
|
+
"react-native": "native",
|
|
189
|
+
flutter: "flutter",
|
|
190
|
+
angular: "angular",
|
|
191
|
+
android: "android",
|
|
192
|
+
ios: "ios",
|
|
193
|
+
};
|
|
194
|
+
|
|
195
|
+
const FAMILY_LABELS = {
|
|
196
|
+
web: "Web (React / Next.js / React Router / Astro)",
|
|
197
|
+
native: "React Native (Expo / bare RN)",
|
|
198
|
+
angular: "Angular (12-15)",
|
|
199
|
+
flutter: "Flutter (V5 stable + V6 beta)",
|
|
200
|
+
android: "Android native (V5 stable + V6 beta)",
|
|
201
|
+
ios: "iOS native (V5 stable)",
|
|
202
|
+
};
|
|
203
|
+
|
|
49
204
|
// ── Helpers ───────────────────────────────────────────────────────────────────
|
|
50
205
|
function ensureDir(dir) {
|
|
51
206
|
if (!fs.existsSync(dir)) fs.mkdirSync(dir, { recursive: true });
|
|
@@ -53,16 +208,166 @@ function ensureDir(dir) {
|
|
|
53
208
|
|
|
54
209
|
// ── IDE target directories ────────────────────────────────────────────────────
|
|
55
210
|
const IDE_TARGETS = {
|
|
56
|
-
claude: { local: ".claude/skills", global: path.join(os.homedir(), ".claude", "skills"),
|
|
211
|
+
claude: { local: ".claude/skills", global: path.join(os.homedir(), ".claude", "skills"), skillFile: "SKILL.md" },
|
|
57
212
|
// Cursor loads agent "skills" from `.cursor/skills/` (not `.cursor/rules/`).
|
|
58
|
-
cursor: { local: ".cursor/skills", global: path.join(os.homedir(), ".cursor", "skills"),
|
|
59
|
-
kiro: { local: ".kiro/skills",
|
|
60
|
-
copilot: { local: ".github",
|
|
213
|
+
cursor: { local: ".cursor/skills", global: path.join(os.homedir(), ".cursor", "skills"), skillFile: "SKILL.md" },
|
|
214
|
+
kiro: { local: ".kiro/skills", global: path.join(os.homedir(), ".kiro", "skills"), skillFile: "SKILL.md" },
|
|
215
|
+
copilot: { local: ".github", global: null, skillFile: null }, // single-file mode
|
|
216
|
+
// Replit Agent reads `.agents/skills/` per docs.replit.com/core-concepts/agent/skills.
|
|
217
|
+
// Global path matches the convention published by vercel-labs/skills.
|
|
218
|
+
replit: { local: ".agents/skills", global: path.join(os.homedir(), ".config", "agents", "skills"), skillFile: "SKILL.md" },
|
|
61
219
|
};
|
|
62
220
|
|
|
63
|
-
//
|
|
64
|
-
//
|
|
65
|
-
//
|
|
221
|
+
// ── Framework detection (inline — no subprocess) ─────────────────────────────
|
|
222
|
+
//
|
|
223
|
+
// Reads package.json + signal files in cwd to determine which family this
|
|
224
|
+
// project belongs to. Returns the family string ("web", "native", "flutter",
|
|
225
|
+
// "angular", "android", "ios") or null if undetectable.
|
|
226
|
+
//
|
|
227
|
+
// We inline this rather than subprocess to @cometchat/skills-cli because:
|
|
228
|
+
// 1. Cold `npx -y` adds 5-15 s on first run — bad first impression
|
|
229
|
+
// 2. Avoids attack surface of auto-installing a separate package
|
|
230
|
+
// 3. The unified installer only needs family resolution, not the CLI's
|
|
231
|
+
// richer detection (router/bundler/env-prefix/SSR strategy etc.)
|
|
232
|
+
//
|
|
233
|
+
// Detection order matters — more specific first:
|
|
234
|
+
// 1. RN (expo / react-native dep) — must come before generic React
|
|
235
|
+
// 2. Next.js (next dep)
|
|
236
|
+
// 3. React Router (any of the v6/v7 deps)
|
|
237
|
+
// 4. Astro (deps OR astro.config.*)
|
|
238
|
+
// 5. Angular (@angular/core dep OR angular.json)
|
|
239
|
+
// 6. Generic React (react / react-dom dep) → web
|
|
240
|
+
// 7. Flutter (pubspec.yaml with `flutter:` key)
|
|
241
|
+
// 8. Android (build.gradle / settings.gradle)
|
|
242
|
+
// 9. iOS (*.xcodeproj, *.xcworkspace, Package.swift with .iOS, Podfile with platform :ios)
|
|
243
|
+
function detectFamily(cwd) {
|
|
244
|
+
const pkgPath = path.join(cwd, "package.json");
|
|
245
|
+
if (fs.existsSync(pkgPath)) {
|
|
246
|
+
try {
|
|
247
|
+
const pkg = JSON.parse(fs.readFileSync(pkgPath, "utf-8"));
|
|
248
|
+
const deps = { ...(pkg.dependencies || {}), ...(pkg.devDependencies || {}) };
|
|
249
|
+
if (deps["expo"] || deps["react-native"]) return "native";
|
|
250
|
+
if (deps["next"]) return "web";
|
|
251
|
+
if (deps["@react-router/dev"] || deps["react-router-dom"] || deps["react-router"]) return "web";
|
|
252
|
+
if (deps["astro"]) return "web";
|
|
253
|
+
if (deps["@angular/core"]) return "angular";
|
|
254
|
+
if (deps["react"] || deps["react-dom"]) return "web";
|
|
255
|
+
} catch { /* malformed package.json — fall through */ }
|
|
256
|
+
}
|
|
257
|
+
|
|
258
|
+
// Astro config exists even before deps install
|
|
259
|
+
for (const ext of ["ts", "mjs", "js", "cjs"]) {
|
|
260
|
+
if (fs.existsSync(path.join(cwd, `astro.config.${ext}`))) return "web";
|
|
261
|
+
}
|
|
262
|
+
|
|
263
|
+
// Flutter — pubspec.yaml with `flutter:` key
|
|
264
|
+
const pubspecPath = path.join(cwd, "pubspec.yaml");
|
|
265
|
+
if (fs.existsSync(pubspecPath)) {
|
|
266
|
+
try {
|
|
267
|
+
const pubspec = fs.readFileSync(pubspecPath, "utf-8");
|
|
268
|
+
if (/^flutter:/m.test(pubspec)) return "flutter";
|
|
269
|
+
} catch { /* fall through */ }
|
|
270
|
+
}
|
|
271
|
+
|
|
272
|
+
// Angular workspace
|
|
273
|
+
if (fs.existsSync(path.join(cwd, "angular.json"))) return "angular";
|
|
274
|
+
|
|
275
|
+
// Android (Gradle-based)
|
|
276
|
+
if (
|
|
277
|
+
fs.existsSync(path.join(cwd, "build.gradle")) ||
|
|
278
|
+
fs.existsSync(path.join(cwd, "build.gradle.kts")) ||
|
|
279
|
+
fs.existsSync(path.join(cwd, "settings.gradle"))
|
|
280
|
+
) {
|
|
281
|
+
return "android";
|
|
282
|
+
}
|
|
283
|
+
|
|
284
|
+
// iOS — Xcode project / workspace, or Package.swift with .iOS, or Podfile with `platform :ios`
|
|
285
|
+
try {
|
|
286
|
+
for (const f of fs.readdirSync(cwd)) {
|
|
287
|
+
if (f.endsWith(".xcodeproj") || f.endsWith(".xcworkspace")) return "ios";
|
|
288
|
+
}
|
|
289
|
+
} catch { /* unreadable cwd — fall through */ }
|
|
290
|
+
const podfilePath = path.join(cwd, "Podfile");
|
|
291
|
+
if (fs.existsSync(podfilePath)) {
|
|
292
|
+
try {
|
|
293
|
+
if (/platform\s+:ios/.test(fs.readFileSync(podfilePath, "utf-8"))) return "ios";
|
|
294
|
+
} catch { /* fall through */ }
|
|
295
|
+
}
|
|
296
|
+
const packageSwiftPath = path.join(cwd, "Package.swift");
|
|
297
|
+
if (fs.existsSync(packageSwiftPath)) {
|
|
298
|
+
try {
|
|
299
|
+
if (/\.iOS\s*\(/.test(fs.readFileSync(packageSwiftPath, "utf-8"))) return "ios";
|
|
300
|
+
} catch { /* fall through */ }
|
|
301
|
+
}
|
|
302
|
+
|
|
303
|
+
return null;
|
|
304
|
+
}
|
|
305
|
+
|
|
306
|
+
function promptFamily() {
|
|
307
|
+
// Refuse to prompt in non-interactive environments — readline would block
|
|
308
|
+
// forever waiting for stdin that never comes (CI, Dockerfile, scripted
|
|
309
|
+
// installs). Tell the user how to recover.
|
|
310
|
+
if (!process.stdin.isTTY) {
|
|
311
|
+
console.error(c.red(`\n Cannot prompt for family in a non-interactive environment.`));
|
|
312
|
+
console.error(` Pass ${c.cyan("--family <name>")} explicitly. Valid:`);
|
|
313
|
+
console.error(` ${Object.keys(FAMILY_LABELS).join(", ")}, all\n`);
|
|
314
|
+
process.exit(1);
|
|
315
|
+
}
|
|
316
|
+
|
|
317
|
+
const families = ["web", "native", "flutter", "angular", "android", "ios"];
|
|
318
|
+
const rl = readline.createInterface({ input: process.stdin, output: process.stdout });
|
|
319
|
+
console.log(`\n ${c.bold("Which framework does your project use?")}\n`);
|
|
320
|
+
families.forEach((f, i) => {
|
|
321
|
+
console.log(` ${c.cyan(String(i + 1))}. ${FAMILY_LABELS[f]}`);
|
|
322
|
+
});
|
|
323
|
+
return new Promise((resolve) => {
|
|
324
|
+
rl.question(`\n Enter 1-${families.length}: `, (answer) => {
|
|
325
|
+
rl.close();
|
|
326
|
+
const idx = parseInt(answer.trim(), 10) - 1;
|
|
327
|
+
if (Number.isNaN(idx) || idx < 0 || idx >= families.length) {
|
|
328
|
+
console.error(c.red(`\n Invalid choice: ${answer}\n`));
|
|
329
|
+
process.exit(1);
|
|
330
|
+
}
|
|
331
|
+
resolve(families[idx]);
|
|
332
|
+
});
|
|
333
|
+
});
|
|
334
|
+
}
|
|
335
|
+
|
|
336
|
+
// Returns an array of families. Most calls return a single-item array;
|
|
337
|
+
// repeated `--family` flags (`--family web --family native`) return multiple,
|
|
338
|
+
// useful for monorepos with both web + RN packages. `--family all` is a single
|
|
339
|
+
// item that means "every family" downstream.
|
|
340
|
+
async function resolveFamilies(args) {
|
|
341
|
+
// 1. Explicit --family flag(s) — repeatable
|
|
342
|
+
const explicit = [];
|
|
343
|
+
for (let i = 0; i < args.length; i++) {
|
|
344
|
+
if (args[i] === "--family" && args[i + 1]) {
|
|
345
|
+
const f = args[i + 1];
|
|
346
|
+
if (f === "all") { explicit.length = 0; explicit.push("all"); break; }
|
|
347
|
+
if (!Object.keys(FAMILY_LABELS).includes(f)) {
|
|
348
|
+
console.error(c.red(`\n Unknown family: ${f}. Valid: ${Object.keys(FAMILY_LABELS).join(", ")}, all\n`));
|
|
349
|
+
process.exit(1);
|
|
350
|
+
}
|
|
351
|
+
if (!explicit.includes(f)) explicit.push(f);
|
|
352
|
+
i++; // skip the value
|
|
353
|
+
}
|
|
354
|
+
}
|
|
355
|
+
if (explicit.length > 0) return explicit;
|
|
356
|
+
|
|
357
|
+
// 2. Auto-detect (inline, no subprocess)
|
|
358
|
+
process.stdout.write(c.dim("\n Detecting framework... "));
|
|
359
|
+
const family = detectFamily(process.cwd());
|
|
360
|
+
if (family) {
|
|
361
|
+
console.log(c.green(`✓ ${family} — ${FAMILY_LABELS[family]}`));
|
|
362
|
+
return [family];
|
|
363
|
+
}
|
|
364
|
+
console.log(c.dim("could not detect from project files"));
|
|
365
|
+
|
|
366
|
+
// 3. Prompt the user (with TTY guard)
|
|
367
|
+
return [await promptFamily()];
|
|
368
|
+
}
|
|
369
|
+
|
|
370
|
+
// ── Install one skill (per-IDE write) ─────────────────────────────────────────
|
|
66
371
|
function installSkill(skill, baseDir, skillFile) {
|
|
67
372
|
const src = path.join(SKILLS_SRC_DIR, skill.name, "SKILL.md");
|
|
68
373
|
if (!fs.existsSync(src)) {
|
|
@@ -87,35 +392,108 @@ function installSkill(skill, baseDir, skillFile) {
|
|
|
87
392
|
return dest;
|
|
88
393
|
}
|
|
89
394
|
|
|
90
|
-
function installCopilotSkills(baseDir) {
|
|
395
|
+
function installCopilotSkills(skillsToInstall, baseDir) {
|
|
91
396
|
ensureDir(baseDir);
|
|
92
397
|
const dest = path.join(baseDir, "copilot-instructions.md");
|
|
93
398
|
let content = "# CometChat Skills\n\n";
|
|
94
|
-
for (const skill of
|
|
399
|
+
for (const skill of skillsToInstall) {
|
|
95
400
|
const src = path.join(SKILLS_SRC_DIR, skill.name, "SKILL.md");
|
|
96
|
-
if (!fs.existsSync(src))
|
|
97
|
-
continue; // skip skills that haven't been promoted yet
|
|
98
|
-
}
|
|
401
|
+
if (!fs.existsSync(src)) continue;
|
|
99
402
|
content += fs.readFileSync(src, "utf8") + "\n\n---\n\n";
|
|
100
403
|
}
|
|
101
404
|
fs.writeFileSync(dest, content, "utf8");
|
|
102
405
|
return dest;
|
|
103
406
|
}
|
|
104
407
|
|
|
408
|
+
// ── Multi-agent picker via vercel-labs/skills ────────────────────────────────
|
|
409
|
+
//
|
|
410
|
+
// Spawns `npx -y skills@<pin> add cometchat-team/cometchat-skills -s <names>`
|
|
411
|
+
// so the interactive multi-agent picker (Claude Code / Cursor / Codex /
|
|
412
|
+
// Cline / Kiro / Replit / 50+ agents) shows. The user picks which agents
|
|
413
|
+
// to write to; the skills CLI handles the per-agent path conventions.
|
|
414
|
+
//
|
|
415
|
+
// We pre-resolve the family-specific skill list (from `resolveFamilies` +
|
|
416
|
+
// SKILLS table) and pass the names via `-s name1 name2 ...` so the user
|
|
417
|
+
// only sees skills relevant to their detected family — not all 100+ in
|
|
418
|
+
// the marketplace.
|
|
419
|
+
//
|
|
420
|
+
// Pin: `skills@1.5.5` was the version verified against this codebase.
|
|
421
|
+
// Bump on intentional re-verification; pre-pin avoids breakage from a
|
|
422
|
+
// future major bump in the upstream CLI.
|
|
423
|
+
const SKILLS_CLI_PIN = "skills@1.5.5";
|
|
424
|
+
const SKILLS_REPO = "cometchat-team/cometchat-skills";
|
|
425
|
+
|
|
426
|
+
async function delegateToSkillsCli({ skills, families, isGlobal }) {
|
|
427
|
+
const skillNames = skills.map(s => s.name);
|
|
428
|
+
const familyLabel = families.includes("all") ? "all" : families.join("+");
|
|
429
|
+
|
|
430
|
+
console.log(`\n ${c.bold(c.cyan("CometChat Skills"))} — ${c.bold(familyLabel)} family — ${skillNames.length} skills`);
|
|
431
|
+
console.log(` ${c.gray("Launching multi-agent picker via vercel-labs/skills...")}\n`);
|
|
432
|
+
|
|
433
|
+
const npxArgs = [
|
|
434
|
+
"-y", // auto-accept the npx install prompt for the skills CLI itself
|
|
435
|
+
SKILLS_CLI_PIN,
|
|
436
|
+
"add",
|
|
437
|
+
SKILLS_REPO,
|
|
438
|
+
"-s", ...skillNames, // space-separated skill names (skills CLI's flag shape)
|
|
439
|
+
];
|
|
440
|
+
if (isGlobal) npxArgs.push("-g");
|
|
441
|
+
|
|
442
|
+
return new Promise((resolve) => {
|
|
443
|
+
const child = spawn("npx", npxArgs, {
|
|
444
|
+
stdio: "inherit",
|
|
445
|
+
shell: false,
|
|
446
|
+
});
|
|
447
|
+
child.on("close", (code) => resolve(code ?? 1));
|
|
448
|
+
child.on("error", (err) => {
|
|
449
|
+
console.error(c.red(`\n ✗ Failed to spawn skills CLI: ${err.message}`));
|
|
450
|
+
console.error(c.dim(` Falling back to legacy direct-write — re-run with --ide <name> to bypass the picker.\n`));
|
|
451
|
+
resolve(2);
|
|
452
|
+
});
|
|
453
|
+
});
|
|
454
|
+
}
|
|
455
|
+
|
|
105
456
|
function printHelp() {
|
|
106
457
|
console.log(`
|
|
107
|
-
${c.bold("cometchat
|
|
458
|
+
${c.bold("@cometchat/skills")} — Install CometChat AI coding skills
|
|
108
459
|
|
|
109
460
|
${c.bold("Usage:")}
|
|
110
|
-
${c.cyan("npx @cometchat/skills add")}
|
|
111
|
-
${c.cyan("npx @cometchat/skills add --
|
|
112
|
-
${c.cyan("npx @cometchat/skills add --ide
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
${c.
|
|
116
|
-
|
|
461
|
+
${c.cyan("npx @cometchat/skills add")} Base install + interactive multi-agent picker
|
|
462
|
+
${c.cyan("npx @cometchat/skills add --family <name>")} Install full family upfront (no runtime expansion)
|
|
463
|
+
${c.cyan("npx @cometchat/skills add --ide <name>")} Direct-write base skills to one IDE (CI/scripted)
|
|
464
|
+
|
|
465
|
+
${c.bold("Two install shapes:")}
|
|
466
|
+
${c.bold("Base install")} (default — no --family flag): writes only the cross-family
|
|
467
|
+
skills (the cometchat dispatcher + cross-family helpers). Once installed,
|
|
468
|
+
open your project in your IDE and run /cometchat — the dispatcher detects
|
|
469
|
+
your framework and asks the agent to install the family-specific skills
|
|
470
|
+
via \`npx @cometchat/skills add --family <X> --ide <Y>\`. Smallest initial
|
|
471
|
+
install, dispatcher routes the rest. Recommended for most users.
|
|
472
|
+
${c.bold("Full family install")} (--family flag): writes the dispatcher + every
|
|
473
|
+
skill registered for that family (web=13, android=31, flutter=28, etc.)
|
|
474
|
+
upfront. Use when you know the project's framework and prefer all skills
|
|
475
|
+
present immediately. Used by power users + CI smoke tests.
|
|
476
|
+
|
|
477
|
+
${c.bold("Family values:")}
|
|
478
|
+
${c.cyan("web")} React / Next.js / React Router / Astro
|
|
479
|
+
${c.cyan("native")} Expo / bare React Native
|
|
480
|
+
${c.cyan("angular")} Angular (12-15)
|
|
481
|
+
${c.cyan("android")} Android native (V5 stable + V6 beta)
|
|
482
|
+
${c.cyan("flutter")} Flutter (V5 stable + V6 beta)
|
|
483
|
+
${c.cyan("ios")} iOS native (V5 stable)
|
|
484
|
+
${c.cyan("all")} Install every skill (legacy v3 behavior)
|
|
485
|
+
|
|
486
|
+
${c.bold("IDE selection (direct-write mode only — default: claude):")}
|
|
487
|
+
${c.cyan("--ide cursor")} ${c.cyan("--ide kiro")} ${c.cyan("--ide copilot")} ${c.cyan("--ide replit")} ${c.cyan("--ide all")}
|
|
117
488
|
|
|
118
|
-
${c.bold("
|
|
489
|
+
${c.bold("Multi-family / monorepo:")}
|
|
490
|
+
${c.cyan("--family web --family native")} Install BOTH families (repeat flag)
|
|
491
|
+
|
|
492
|
+
${c.bold("Other:")}
|
|
493
|
+
${c.cyan("--global")} Install globally (~/.claude/skills/, etc.)
|
|
494
|
+
${c.cyan("--clean")} Wipe existing cometchat-* skill dirs before install (direct-write mode only)
|
|
495
|
+
${c.cyan("--list")} Show every skill with its family tags
|
|
496
|
+
${c.cyan("--no-picker")} Force direct-write even in interactive TTY (useful for testing the legacy path)
|
|
119
497
|
|
|
120
498
|
${c.bold("After installing, open your project in your IDE and run:")}
|
|
121
499
|
${c.cyan("/cometchat")}
|
|
@@ -140,18 +518,103 @@ async function main() {
|
|
|
140
518
|
|
|
141
519
|
const isGlobal = args.includes("--global") || args.includes("-g");
|
|
142
520
|
const listOnly = args.includes("--list") || args.includes("-l");
|
|
521
|
+
const isClean = args.includes("--clean");
|
|
143
522
|
const ideIdx = args.indexOf("--ide");
|
|
144
523
|
const ideArg = ideIdx !== -1 ? args[ideIdx + 1] : "claude";
|
|
145
524
|
|
|
146
525
|
if (listOnly) {
|
|
147
526
|
console.log(`\n ${c.bold("Available skills:")}\n`);
|
|
148
527
|
for (const s of SKILLS) {
|
|
149
|
-
console.log(` ${c.cyan(s.name)}`);
|
|
528
|
+
console.log(` ${c.cyan(s.name)} ${c.dim(`[${s.families.join(", ")}]`)}`);
|
|
150
529
|
console.log(` ${c.dim(s.description)}\n`);
|
|
151
530
|
}
|
|
152
531
|
process.exit(0);
|
|
153
532
|
}
|
|
154
533
|
|
|
534
|
+
// ── Install mode selection ─────────────────────────────────────────────
|
|
535
|
+
//
|
|
536
|
+
// Three valid invocation shapes:
|
|
537
|
+
//
|
|
538
|
+
// 1. `npx @cometchat/skills add` (TTY, no --family, no --ide)
|
|
539
|
+
// → BASE INSTALL: install only cross-family skills (cometchat
|
|
540
|
+
// dispatcher + cometchat-calls + i18n + a11y) via the multi-agent
|
|
541
|
+
// picker. The dispatcher detects the framework AT RUNTIME inside
|
|
542
|
+
// the user's IDE and asks the agent to install family-specific
|
|
543
|
+
// skills via `npx @cometchat/skills add --family <X> --ide <Y>`.
|
|
544
|
+
// Smallest initial install; routing is the dispatcher's job.
|
|
545
|
+
//
|
|
546
|
+
// 2. `npx @cometchat/skills add --family <X>` (TTY)
|
|
547
|
+
// → FAMILY INSTALL: install the dispatcher + every skill registered
|
|
548
|
+
// for family X (web=13, android=31, etc.) via the picker. Use this
|
|
549
|
+
// when you know upfront which family you want and prefer all
|
|
550
|
+
// skills present immediately.
|
|
551
|
+
//
|
|
552
|
+
// 3. `npx @cometchat/skills add --ide <Y>` (or non-TTY, e.g. CI)
|
|
553
|
+
// → DIRECT WRITE: skips the picker and writes directly to one IDE's
|
|
554
|
+
// directory. With --family, writes the family subset; without, falls
|
|
555
|
+
// back to BASE skills (CI smoke). Used by Dockerfiles and the
|
|
556
|
+
// legacy single-agent flow.
|
|
557
|
+
const ideExplicit = ideIdx !== -1;
|
|
558
|
+
const familyExplicit = args.includes("--family");
|
|
559
|
+
const isTTY = process.stdin.isTTY && process.stdout.isTTY;
|
|
560
|
+
const skipPicker = ideExplicit || !isTTY || args.includes("--no-picker");
|
|
561
|
+
|
|
562
|
+
// Resolve skill set based on mode:
|
|
563
|
+
// - --family X → install the dispatcher + every skill registered for X
|
|
564
|
+
// (legacy power-user / CI flow; everything present immediately)
|
|
565
|
+
// - No --family (with or without --ide) → BASE install only. The
|
|
566
|
+
// dispatcher handles family-specific install at runtime via its own
|
|
567
|
+
// `npx @cometchat/skills add --family <X>` invocation logic.
|
|
568
|
+
let skillsToInstall;
|
|
569
|
+
let families;
|
|
570
|
+
if (familyExplicit) {
|
|
571
|
+
families = await resolveFamilies(args);
|
|
572
|
+
if (families.includes("all")) {
|
|
573
|
+
skillsToInstall = SKILLS;
|
|
574
|
+
} else {
|
|
575
|
+
const seen = new Set();
|
|
576
|
+
skillsToInstall = [];
|
|
577
|
+
for (const fam of families) {
|
|
578
|
+
for (const s of SKILLS) {
|
|
579
|
+
if (s.families.includes(fam) && !seen.has(s.name)) {
|
|
580
|
+
seen.add(s.name);
|
|
581
|
+
skillsToInstall.push(s);
|
|
582
|
+
}
|
|
583
|
+
}
|
|
584
|
+
}
|
|
585
|
+
}
|
|
586
|
+
|
|
587
|
+
// If no pattern skills matched (only the dispatcher), all selected
|
|
588
|
+
// families are "coming soon" — bail with a friendly message rather than
|
|
589
|
+
// installing a half-broken set.
|
|
590
|
+
const patternSkills = skillsToInstall.filter(s => s.name !== "cometchat");
|
|
591
|
+
if (patternSkills.length === 0) {
|
|
592
|
+
const labels = families.map(f => FAMILY_LABELS[f] || f).join(", ");
|
|
593
|
+
console.log(c.yellow(`\n ⚠ Pattern skills for ${labels} aren't published yet.`));
|
|
594
|
+
console.log(` Supported families today: ${c.cyan("web")}, ${c.cyan("native")}, ${c.cyan("angular")}, ${c.cyan("android")}, ${c.cyan("flutter")}, ${c.cyan("ios")}.`);
|
|
595
|
+
console.log(` Run with one of those, or wait for ${families.join(" + ")} skills to ship.\n`);
|
|
596
|
+
process.exit(1);
|
|
597
|
+
}
|
|
598
|
+
} else {
|
|
599
|
+
// Default: base install only (whether interactive or with --ide).
|
|
600
|
+
// The dispatcher detects the framework at runtime and installs the
|
|
601
|
+
// family-specific skills via its own runtime npx invocation.
|
|
602
|
+
skillsToInstall = BASE_SKILLS;
|
|
603
|
+
families = ["base"];
|
|
604
|
+
console.log(`\n ${c.bold(c.cyan("CometChat Skills"))} ${c.dim("(base install — dispatcher routes the rest at runtime)")}`);
|
|
605
|
+
console.log(` ${c.gray(`Installing ${BASE_SKILLS.length} cross-family ${BASE_SKILLS.length === 1 ? "skill" : "skills"}: ${BASE_SKILLS.map(s => s.name).join(", ")}.`)}`);
|
|
606
|
+
console.log(` ${c.gray("After install, open your project in your IDE → /cometchat detects your framework and asks the agent to install family-specific skills on demand.")}\n`);
|
|
607
|
+
}
|
|
608
|
+
|
|
609
|
+
if (!skipPicker) {
|
|
610
|
+
const exitCode = await delegateToSkillsCli({
|
|
611
|
+
skills: skillsToInstall,
|
|
612
|
+
families,
|
|
613
|
+
isGlobal,
|
|
614
|
+
});
|
|
615
|
+
process.exit(exitCode);
|
|
616
|
+
}
|
|
617
|
+
|
|
155
618
|
const targets = ideArg === "all" ? Object.keys(IDE_TARGETS) : [ideArg];
|
|
156
619
|
|
|
157
620
|
for (const ide of targets) {
|
|
@@ -171,23 +634,40 @@ async function main() {
|
|
|
171
634
|
? `global ${c.gray(`(${target.global}/`)}`
|
|
172
635
|
: `local ${c.gray(`(${target.local}/)`)}`;
|
|
173
636
|
|
|
174
|
-
|
|
637
|
+
const familyLabel = families.includes("all") ? "all" : families.join("+");
|
|
638
|
+
console.log(`\n ${c.bold(c.cyan("CometChat Skills"))} — ${ide} — ${c.bold(familyLabel)} family\n`);
|
|
175
639
|
console.log(` Scope: ${scopeLabel}\n`);
|
|
176
640
|
|
|
177
641
|
ensureDir(baseDir);
|
|
178
642
|
|
|
643
|
+
// --clean: wipe existing cometchat-* skill dirs in baseDir before install.
|
|
644
|
+
// Avoids stale skills accumulating across multiple --family runs in the
|
|
645
|
+
// same project (e.g. user runs --family web then later switches to
|
|
646
|
+
// --family native and wants only the new family present). Only touches
|
|
647
|
+
// dirs prefixed `cometchat` so we never blow away unrelated skills.
|
|
648
|
+
if (isClean && ide !== "copilot" && fs.existsSync(baseDir)) {
|
|
649
|
+
let wiped = 0;
|
|
650
|
+
for (const entry of fs.readdirSync(baseDir)) {
|
|
651
|
+
if (entry === "cometchat" || entry.startsWith("cometchat-")) {
|
|
652
|
+
fs.rmSync(path.join(baseDir, entry), { recursive: true, force: true });
|
|
653
|
+
wiped++;
|
|
654
|
+
}
|
|
655
|
+
}
|
|
656
|
+
if (wiped > 0) console.log(c.dim(` ✓ cleaned ${wiped} existing cometchat-* skill ${wiped === 1 ? "dir" : "dirs"}\n`));
|
|
657
|
+
}
|
|
658
|
+
|
|
179
659
|
if (ide === "copilot") {
|
|
180
660
|
const spinner = ora ? ora({ text: "copilot-instructions.md", prefixText: " " }).start() : null;
|
|
181
661
|
try {
|
|
182
|
-
|
|
183
|
-
if (spinner) spinner.succeed(c.green("✓ ") + c.bold("copilot-instructions.md") + ` ${c.dim(
|
|
184
|
-
else console.log(` ✓ copilot-instructions.md`);
|
|
662
|
+
installCopilotSkills(skillsToInstall, baseDir);
|
|
663
|
+
if (spinner) spinner.succeed(c.green("✓ ") + c.bold("copilot-instructions.md") + ` ${c.dim(`(${skillsToInstall.length} skills concatenated)`)}`);
|
|
664
|
+
else console.log(` ✓ copilot-instructions.md (${skillsToInstall.length} skills)`);
|
|
185
665
|
} catch (err) {
|
|
186
666
|
if (spinner) spinner.fail(c.red(`✗ copilot-instructions.md: ${err.message}`));
|
|
187
667
|
else console.error(` ✗ copilot-instructions.md: ${err.message}`);
|
|
188
668
|
}
|
|
189
669
|
} else {
|
|
190
|
-
for (const skill of
|
|
670
|
+
for (const skill of skillsToInstall) {
|
|
191
671
|
const spinner = ora ? ora({ text: skill.name, prefixText: " " }).start() : null;
|
|
192
672
|
try {
|
|
193
673
|
installSkill(skill, baseDir, target.skillFile);
|