🚀 Socket Launch Week Day 5:Introducing Repository Access Permissions and Custom Roles.Learn more
Sign In

@cometchat/skills

Package Overview
Dependencies
Maintainers
12
Versions
8
Alerts
File Explorer

Advanced tools

Socket logo

Install Socket

Detect and block malicious and high-risk dependencies

Install

@cometchat/skills - npm Package Compare versions

Comparing version
4.0.0
to
4.1.0
+162
-28
bin/install.js

@@ -9,2 +9,3 @@ #!/usr/bin/env node

const readline = require("readline");
const { spawn } = require("child_process");

@@ -161,2 +162,22 @@ // ── Lazy-load optional deps ───────────────────────────────────────────────────

// ── Base skills (cross-family) ────────────────────────────────────────────────
//
// Skills registered for ALL six families. These are the baseline a dispatcher
// needs to detect framework and route — they're installed in the default
// interactive flow, before any family is resolved. The dispatcher (read at
// runtime in the user's IDE) detects the framework and asks the agent to
// install the relevant family skills via:
//
// npx @cometchat/skills add --family <X> --ide <Y>
//
// (Logic already in `skills/cometchat/SKILL.md` Step 1 — "If `framework` is
// X AND `cometchat-{X}-core` is NOT loaded: <install command>".)
//
// This list grows automatically as more cross-family skills are registered
// (e.g. when the calls work merges, cometchat-calls/i18n/a11y join).
const ALL_FAMILIES_SET = ["web", "native", "flutter", "angular", "android", "ios"];
const BASE_SKILLS = SKILLS.filter(s =>
ALL_FAMILIES_SET.every(f => s.families.includes(f))
);
// ── Framework → family routing ────────────────────────────────────────────────

@@ -389,2 +410,50 @@ const FRAMEWORK_TO_FAMILY = {

// ── Multi-agent picker via vercel-labs/skills ────────────────────────────────
//
// Spawns `npx -y skills@<pin> add cometchat-team/cometchat-skills -s <names>`
// so the interactive multi-agent picker (Claude Code / Cursor / Codex /
// Cline / Kiro / Replit / 50+ agents) shows. The user picks which agents
// to write to; the skills CLI handles the per-agent path conventions.
//
// We pre-resolve the family-specific skill list (from `resolveFamilies` +
// SKILLS table) and pass the names via `-s name1 name2 ...` so the user
// only sees skills relevant to their detected family — not all 100+ in
// the marketplace.
//
// Pin: `skills@1.5.5` was the version verified against this codebase.
// Bump on intentional re-verification; pre-pin avoids breakage from a
// future major bump in the upstream CLI.
const SKILLS_CLI_PIN = "skills@1.5.5";
const SKILLS_REPO = "cometchat-team/cometchat-skills";
async function delegateToSkillsCli({ skills, families, isGlobal }) {
const skillNames = skills.map(s => s.name);
const familyLabel = families.includes("all") ? "all" : families.join("+");
console.log(`\n ${c.bold(c.cyan("CometChat Skills"))} — ${c.bold(familyLabel)} family — ${skillNames.length} skills`);
console.log(` ${c.gray("Launching multi-agent picker via vercel-labs/skills...")}\n`);
const npxArgs = [
"-y", // auto-accept the npx install prompt for the skills CLI itself
SKILLS_CLI_PIN,
"add",
SKILLS_REPO,
"-s", ...skillNames, // space-separated skill names (skills CLI's flag shape)
];
if (isGlobal) npxArgs.push("-g");
return new Promise((resolve) => {
const child = spawn("npx", npxArgs, {
stdio: "inherit",
shell: false,
});
child.on("close", (code) => resolve(code ?? 1));
child.on("error", (err) => {
console.error(c.red(`\n ✗ Failed to spawn skills CLI: ${err.message}`));
console.error(c.dim(` Falling back to legacy direct-write — re-run with --ide <name> to bypass the picker.\n`));
resolve(2);
});
});
}
function printHelp() {

@@ -395,5 +464,18 @@ console.log(`

${c.bold("Usage:")}
${c.cyan("npx @cometchat/skills add")} Auto-detect framework + install
${c.cyan("npx @cometchat/skills add --family <name>")} Override detection
${c.cyan("npx @cometchat/skills add")} Base install + interactive multi-agent picker
${c.cyan("npx @cometchat/skills add --family <name>")} Install full family upfront (no runtime expansion)
${c.cyan("npx @cometchat/skills add --ide <name>")} Direct-write base skills to one IDE (CI/scripted)
${c.bold("Two install shapes:")}
${c.bold("Base install")} (default — no --family flag): writes only the cross-family
skills (the cometchat dispatcher + cross-family helpers). Once installed,
open your project in your IDE and run /cometchat — the dispatcher detects
your framework and asks the agent to install the family-specific skills
via \`npx @cometchat/skills add --family <X> --ide <Y>\`. Smallest initial
install, dispatcher routes the rest. Recommended for most users.
${c.bold("Full family install")} (--family flag): writes the dispatcher + every
skill registered for that family (web=13, android=31, flutter=28, etc.)
upfront. Use when you know the project's framework and prefer all skills
present immediately. Used by power users + CI smoke tests.
${c.bold("Family values:")}

@@ -408,3 +490,3 @@ ${c.cyan("web")} React / Next.js / React Router / Astro

${c.bold("IDE selection (default: claude):")}
${c.bold("IDE selection (direct-write mode only — default: claude):")}
${c.cyan("--ide cursor")} ${c.cyan("--ide kiro")} ${c.cyan("--ide copilot")} ${c.cyan("--ide replit")} ${c.cyan("--ide all")}

@@ -417,4 +499,5 @@

${c.cyan("--global")} Install globally (~/.claude/skills/, etc.)
${c.cyan("--clean")} Wipe existing cometchat-* skill dirs before install
${c.cyan("--clean")} Wipe existing cometchat-* skill dirs before install (direct-write mode only)
${c.cyan("--list")} Show every skill with its family tags
${c.cyan("--no-picker")} Force direct-write even in interactive TTY (useful for testing the legacy path)

@@ -457,33 +540,84 @@ ${c.bold("After installing, open your project in your IDE and run:")}

// Resolve which families to install (flag(s) → detect → prompt).
const families = await resolveFamilies(args);
// ── Install mode selection ─────────────────────────────────────────────
//
// Three valid invocation shapes:
//
// 1. `npx @cometchat/skills add` (TTY, no --family, no --ide)
// → BASE INSTALL: install only cross-family skills (cometchat
// dispatcher + cometchat-calls + i18n + a11y) via the multi-agent
// picker. The dispatcher detects the framework AT RUNTIME inside
// the user's IDE and asks the agent to install family-specific
// skills via `npx @cometchat/skills add --family <X> --ide <Y>`.
// Smallest initial install; routing is the dispatcher's job.
//
// 2. `npx @cometchat/skills add --family <X>` (TTY)
// → FAMILY INSTALL: install the dispatcher + every skill registered
// for family X (web=13, android=31, etc.) via the picker. Use this
// when you know upfront which family you want and prefer all
// skills present immediately.
//
// 3. `npx @cometchat/skills add --ide <Y>` (or non-TTY, e.g. CI)
// → DIRECT WRITE: skips the picker and writes directly to one IDE's
// directory. With --family, writes the family subset; without, falls
// back to BASE skills (CI smoke). Used by Dockerfiles and the
// legacy single-agent flow.
const ideExplicit = ideIdx !== -1;
const familyExplicit = args.includes("--family");
const isTTY = process.stdin.isTTY && process.stdout.isTTY;
const skipPicker = ideExplicit || !isTTY || args.includes("--no-picker");
// Build the set of skills to install — union over all selected families.
// "all" is a singleton meaning "every published skill" (legacy v3 behavior).
// Resolve skill set based on mode:
// - --family X → install the dispatcher + every skill registered for X
// (legacy power-user / CI flow; everything present immediately)
// - No --family (with or without --ide) → BASE install only. The
// dispatcher handles family-specific install at runtime via its own
// `npx @cometchat/skills add --family <X>` invocation logic.
let skillsToInstall;
if (families.includes("all")) {
skillsToInstall = SKILLS;
} else {
const seen = new Set();
skillsToInstall = [];
for (const fam of families) {
for (const s of SKILLS) {
if (s.families.includes(fam) && !seen.has(s.name)) {
seen.add(s.name);
skillsToInstall.push(s);
let families;
if (familyExplicit) {
families = await resolveFamilies(args);
if (families.includes("all")) {
skillsToInstall = SKILLS;
} else {
const seen = new Set();
skillsToInstall = [];
for (const fam of families) {
for (const s of SKILLS) {
if (s.families.includes(fam) && !seen.has(s.name)) {
seen.add(s.name);
skillsToInstall.push(s);
}
}
}
}
// If no pattern skills matched (only the dispatcher), all selected
// families are "coming soon" — bail with a friendly message rather than
// installing a half-broken set.
const patternSkills = skillsToInstall.filter(s => s.name !== "cometchat");
if (patternSkills.length === 0) {
const labels = families.map(f => FAMILY_LABELS[f] || f).join(", ");
console.log(c.yellow(`\n ⚠ Pattern skills for ${labels} aren't published yet.`));
console.log(` Supported families today: ${c.cyan("web")}, ${c.cyan("native")}, ${c.cyan("angular")}, ${c.cyan("android")}, ${c.cyan("flutter")}, ${c.cyan("ios")}.`);
console.log(` Run with one of those, or wait for ${families.join(" + ")} skills to ship.\n`);
process.exit(1);
}
} else {
// Default: base install only (whether interactive or with --ide).
// The dispatcher detects the framework at runtime and installs the
// family-specific skills via its own runtime npx invocation.
skillsToInstall = BASE_SKILLS;
families = ["base"];
console.log(`\n ${c.bold(c.cyan("CometChat Skills"))} ${c.dim("(base install — dispatcher routes the rest at runtime)")}`);
console.log(` ${c.gray(`Installing ${BASE_SKILLS.length} cross-family ${BASE_SKILLS.length === 1 ? "skill" : "skills"}: ${BASE_SKILLS.map(s => s.name).join(", ")}.`)}`);
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`);
}
// If no pattern skills matched (only the dispatcher), all selected families
// are "coming soon" — bail with a friendly message rather than installing a
// half-broken set.
const patternSkills = skillsToInstall.filter(s => s.name !== "cometchat");
if (patternSkills.length === 0) {
const labels = families.map(f => FAMILY_LABELS[f] || f).join(", ");
console.log(c.yellow(`\n ⚠ Pattern skills for ${labels} aren't published yet.`));
console.log(` Supported families today: ${c.cyan("web")}, ${c.cyan("native")}, ${c.cyan("angular")}, ${c.cyan("android")}, ${c.cyan("flutter")}, ${c.cyan("ios")}.`);
console.log(` Run with one of those, or wait for ${families.join(" + ")} skills to ship.\n`);
process.exit(1);
if (!skipPicker) {
const exitCode = await delegateToSkillsCli({
skills: skillsToInstall,
families,
isGlobal,
});
process.exit(exitCode);
}

@@ -490,0 +624,0 @@

+1
-1
{
"name": "@cometchat/skills",
"version": "4.0.0",
"version": "4.1.0",
"publishConfig": {

@@ -5,0 +5,0 @@ "access": "public"

@@ -13,3 +13,3 @@ # cometchat-skills

That's it — one command for every supported framework. The installer detects what you're working with (React, Next.js, React Router, Astro, Expo, bare React Native, Angular, native Android, Flutter, or native iOS) from your project and installs the right skills.
That's it — one command for every supported framework. The installer detects what you're working with (React, Next.js, React Router, Astro, Expo, bare React Native, Angular, native Android, Flutter, or native iOS) from your project, then opens an interactive picker so you can choose which AI agents to install for — Claude Code, Cursor, Codex, Cline, Kiro, Replit Agent, and [50+ more](https://github.com/vercel-labs/skills) all in one pass.

@@ -28,4 +28,44 @@ Override detection if needed:

Supported IDEs: Claude Code (default), Cursor, Kiro, VS Code Copilot, Replit Agent. Use `--ide <name>` to target a specific one, or `--ide all`. Replit users: skills land in `.agents/skills/` automatically when you pass `--ide replit`.
### Two install shapes
**Base install (default, recommended)** — `npx @cometchat/skills add` writes only the cross-family skills (the `cometchat` dispatcher and friends). Smallest initial install. After it lands, open your project in your IDE and run `/cometchat`:
1. The dispatcher detects your framework (Vite + React → `web`, Expo → `native`, etc.)
2. It asks the agent to install family-specific skills on demand via `npx @cometchat/skills add --family <X> --ide <Y>`
3. The agent gets the 13 web skills (or 31 android, 28 flutter, etc.) at exactly the moment they're needed
4. Integration continues with the full skill set loaded
You install once with the multi-agent picker (Claude Code, Cursor, Codex, Cline, Kiro, Replit Agent, [50+ more](https://github.com/vercel-labs/skills)); the dispatcher handles framework-specific expansion as the project actually needs it.
**Full family install** — `npx @cometchat/skills add --family <name>` writes the dispatcher + every skill for that family upfront (web=13, android=31, flutter=28, etc.). Use when you know the framework upfront and want all skills present without runtime expansion. Power users + CI smoke tests.
```bash
# Base install (recommended) — picker + dispatcher routes the rest
npx @cometchat/skills add
# Full family install — power-user / CI flow
npx @cometchat/skills add --family web # all 13 web skills upfront
npx @cometchat/skills add --family native # all 13 RN skills upfront
npx @cometchat/skills add --family android # all 31 Android skills upfront
# ... etc
```
### Direct-write to one IDE (CI / Dockerfile)
When stdin isn't a TTY (CI, Docker), or when you pass `--ide <name>`, the picker is skipped and skills are written directly to one IDE's directory. Default is base install; pass `--family <name>` for the full family install.
```bash
npx @cometchat/skills add --ide claude # base install to .claude/skills/
npx @cometchat/skills add --ide cursor # base install to .cursor/skills/
npx @cometchat/skills add --ide kiro # base install to .kiro/skills/
npx @cometchat/skills add --ide replit # base install to .agents/skills/
npx @cometchat/skills add --ide copilot # base install to .github/copilot-instructions.md
npx @cometchat/skills add --ide all # write base install to every supported IDE
npx @cometchat/skills add --ide claude --family web # full web family install to .claude/skills/
```
Direct-write supports 10 agents: `claude`, `cursor`, `kiro`, `replit`, `copilot`, `continue`, `cline`, `aider`, `codex`, `gemini`. The interactive picker supports 55+ via the vercel-labs/skills ecosystem.
Pass `--no-picker` to force direct-write even in an interactive terminal.
> **Migrating from v3?** `npx @cometchat/skills-native add` still works (with a deprecation notice). New projects should use the unified command.

@@ -32,0 +72,0 @@

@@ -1281,2 +1281,30 @@ ---

6a. **Flex parents that hold a `CometChatMessageList` MUST set `minHeight: 0`** (and `minWidth: 0` for horizontal flex parents). The W3C default `min-height: auto` makes flex children refuse to shrink below their intrinsic content size — so once the conversation grows past the viewport, the list pushes the composer below the fold and the layout breaks. **This is the canonical chat-layout bug** — works fine for short conversations, breaks for long ones. The fix is one CSS property; the diagnosis takes hours if you don't know the rule.
```tsx
/* ✓ CORRECT — header + list + composer with the flex-shrink trap fixed */
<div style={{ display: "flex", flexDirection: "column", height: "100vh" }}>
<div style={{ flex: 1, display: "flex", flexDirection: "column", minHeight: 0 }}>
<div style={{ flex: "0 0 auto" }}>
<CometChatMessageHeader user={user} />
</div>
<div style={{ flex: "1 1 0", minHeight: 0, overflow: "hidden" }}>
<CometChatMessageList user={user} hideReplyInThreadOption />
</div>
<div style={{ flex: "0 0 auto" }}>
<CometChatMessageComposer user={user} />
</div>
</div>
</div>
/* ✗ WRONG — list grows past the viewport once messages exceed visible area */
<div style={{ display: "flex", flexDirection: "column", height: "100vh" }}>
<CometChatMessageHeader user={user} />
<CometChatMessageList user={user} /> {/* takes intrinsic height, no scroll */}
<CometChatMessageComposer user={user} /> {/* falls off the bottom */}
</div>
```
The wrap-each-component-in-a-flex-sized-div pattern is what makes this work. Don't pass the kit components directly as flex children — wrap them.
7. **Resolve target users/groups before rendering CometChat components.** Use `CometChat.getUser(uid)` or `CometChat.getGroup(guid)` to get the full `CometChat.User` or `CometChat.Group` object. Do not pass a raw UID string to `user` props -- they expect object instances.

@@ -1283,0 +1311,0 @@

@@ -471,8 +471,13 @@ ---

### Container height
### Container height (and the flex-shrink trap that breaks chat layouts)
CometChat components fill 100% of their container. The most common visual bug is components rendering with zero height because their container has no explicit dimensions. Always ensure the chat container has a height:
CometChat components fill 100% of their container. Two visual bugs to avoid:
**Bug 1 — zero height:** components render with zero height because the container has no explicit dimensions.
**Bug 2 — message list grows past the viewport:** the list scrolls fine until it has too many messages, then pushes the composer below the fold. **This is the classic flex-shrink trap.**
The hard rule for two-pane / header+list+composer layouts: every flex container in the chain MUST have `minHeight: 0` (and `minWidth: 0` for horizontal flex). Without it, browsers default flex-children to `min-height: auto` (their intrinsic content size), so the list grows beyond the parent's bounds as messages accumulate.
```tsx
/* CORRECT: explicit height */
/* ✓ CORRECT: explicit height for a single-component surface */
<div style={{ height: "100vh" }}>

@@ -482,16 +487,59 @@ <CometChatConversations ... />

/* CORRECT: flex layout with bounded parent */
/* ✓ CORRECT: header + list + composer with the flex-shrink trap fixed */
<div style={{ display: "flex", flexDirection: "column", height: "100vh" }}>
<nav>...</nav>
<div style={{ flex: 1 }}>
<CometChatConversations ... />
<div style={{
flex: 1,
display: "flex",
flexDirection: "column",
minHeight: 0, // ← THIS IS THE HARD RULE — without it, list grows past the viewport
}}>
<div style={{ flex: "0 0 auto" }}>
<CometChatMessageHeader user={user} />
</div>
<div style={{ flex: "1 1 0", minHeight: 0, overflow: "hidden" }}>
<CometChatMessageList user={user} />
</div>
<div style={{ flex: "0 0 auto" }}>
<CometChatMessageComposer user={user} />
</div>
</div>
</div>
/* WRONG: no height constraint -- component collapses to zero */
/* ✓ CORRECT: two-pane (sidebar + active chat) — both axes need min-{width,height}: 0 */
<div style={{ display: "flex", height: "100vh" }}>
<div style={{ width: 360, display: "flex", flexDirection: "column" }}>
<CometChatConversations onItemClick={...} />
</div>
<div style={{
flex: 1,
display: "flex",
flexDirection: "column",
minWidth: 0, // ← horizontal flex parent: prevents content from forcing horizontal scroll
minHeight: 0, // ← vertical flex (the inner column): prevents the list-overflow bug
}}>
{/* header / list / composer wrapped as above */}
</div>
</div>
/* ✗ WRONG: no height constraint — component collapses to zero */
<div>
<CometChatConversations ... />
</div>
/* ✗ WRONG: flex parent without minHeight: 0 — list grows past the viewport once
you accumulate more messages than fit on-screen. Composer falls off the bottom. */
<div style={{ display: "flex", flexDirection: "column", height: "100vh" }}>
<CometChatMessageHeader user={user} />
<CometChatMessageList user={user} /> {/* takes intrinsic content height */}
<CometChatMessageComposer user={user} /> {/* gets pushed below the fold */}
</div>
```
**Why `minHeight: 0` is non-obvious:** the W3C spec sets the default `min-height` of a flex item to `auto` (its intrinsic content height). For a scrollable list inside a flex column, this means the list refuses to shrink below its content even when the parent is bounded. Setting `minHeight: 0` on the flex parent overrides this, letting the list shrink and scroll within the bounded container instead of overflowing it.
**The rule, restated as something to grep for:**
> Every flex container that holds `CometChatMessageList` (directly or indirectly) MUST have `minHeight: 0` on it. Same for `minWidth: 0` on horizontal flex parents. Skip this and the layout works for short conversations and breaks for long ones.
### Vite dependency optimization

@@ -498,0 +546,0 @@

Sorry, the diff of this file is too big to display