@cometchat/skills-cli 2.0.0 → 2.0.1
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/dist/index.js +532 -68
- package/dist/registry/v6/features/catalog.json +1 -1
- package/package.json +2 -2
package/dist/index.js
CHANGED
|
@@ -1350,6 +1350,128 @@ function checkOverwriteSafetyBatch(root, framework, filePaths) {
|
|
|
1350
1350
|
return filePaths.map((p2) => checkOverwriteSafety(root, framework, p2));
|
|
1351
1351
|
}
|
|
1352
1352
|
|
|
1353
|
+
// src/utils/env-file.ts
|
|
1354
|
+
import { readFileSync as readFileSync7, writeFileSync as writeFileSync4 } from "node:fs";
|
|
1355
|
+
import { join as join7 } from "node:path";
|
|
1356
|
+
var PLACEHOLDER_SENTINEL = "YOUR_";
|
|
1357
|
+
var PLACEHOLDER_SUFFIX = "_HERE";
|
|
1358
|
+
function envFileNameFor(framework) {
|
|
1359
|
+
return framework === "nextjs" ? ".env.local" : ".env";
|
|
1360
|
+
}
|
|
1361
|
+
function placeholderFor(varName) {
|
|
1362
|
+
let stripped = varName.replace(/^[A-Z]+_/, "");
|
|
1363
|
+
stripped = stripped.replace(/^COMETCHAT_/, "");
|
|
1364
|
+
return `${PLACEHOLDER_SENTINEL}${stripped}${PLACEHOLDER_SUFFIX}`;
|
|
1365
|
+
}
|
|
1366
|
+
function isPlaceholder(value) {
|
|
1367
|
+
const trimmed = value.trim();
|
|
1368
|
+
return trimmed.startsWith(PLACEHOLDER_SENTINEL) && trimmed.endsWith(PLACEHOLDER_SUFFIX);
|
|
1369
|
+
}
|
|
1370
|
+
function parseEnvKeys(content) {
|
|
1371
|
+
const keys = /* @__PURE__ */ new Set();
|
|
1372
|
+
for (const line of content.split(/\r?\n/)) {
|
|
1373
|
+
const trimmed = line.trim();
|
|
1374
|
+
if (!trimmed || trimmed.startsWith("#")) continue;
|
|
1375
|
+
const eq = trimmed.indexOf("=");
|
|
1376
|
+
if (eq === -1) continue;
|
|
1377
|
+
const key = trimmed.slice(0, eq).trim();
|
|
1378
|
+
if (key) keys.add(key);
|
|
1379
|
+
}
|
|
1380
|
+
return keys;
|
|
1381
|
+
}
|
|
1382
|
+
function parseEnvPairs(content) {
|
|
1383
|
+
const pairs = /* @__PURE__ */ new Map();
|
|
1384
|
+
for (const line of content.split(/\r?\n/)) {
|
|
1385
|
+
const trimmed = line.trim();
|
|
1386
|
+
if (!trimmed || trimmed.startsWith("#")) continue;
|
|
1387
|
+
const eq = trimmed.indexOf("=");
|
|
1388
|
+
if (eq === -1) continue;
|
|
1389
|
+
const key = trimmed.slice(0, eq).trim();
|
|
1390
|
+
let value = trimmed.slice(eq + 1).trim();
|
|
1391
|
+
if (value.startsWith('"') && value.endsWith('"') || value.startsWith("'") && value.endsWith("'")) {
|
|
1392
|
+
value = value.slice(1, -1);
|
|
1393
|
+
}
|
|
1394
|
+
const commentIdx = value.indexOf(" #");
|
|
1395
|
+
if (commentIdx !== -1) {
|
|
1396
|
+
value = value.slice(0, commentIdx).trim();
|
|
1397
|
+
}
|
|
1398
|
+
if (key) pairs.set(key, value);
|
|
1399
|
+
}
|
|
1400
|
+
return pairs;
|
|
1401
|
+
}
|
|
1402
|
+
function writeEnvFile(args) {
|
|
1403
|
+
const { projectRoot, framework, envVars } = args;
|
|
1404
|
+
const fileName = envFileNameFor(framework);
|
|
1405
|
+
const fullPath = join7(projectRoot, fileName);
|
|
1406
|
+
let existing = "";
|
|
1407
|
+
if (pathExists(fullPath)) {
|
|
1408
|
+
try {
|
|
1409
|
+
existing = readFileSync7(fullPath, "utf8");
|
|
1410
|
+
} catch {
|
|
1411
|
+
existing = "";
|
|
1412
|
+
}
|
|
1413
|
+
}
|
|
1414
|
+
const presentKeys = parseEnvKeys(existing);
|
|
1415
|
+
const toWrite = [];
|
|
1416
|
+
const skipped = [];
|
|
1417
|
+
for (const v of envVars) {
|
|
1418
|
+
if (presentKeys.has(v.name)) {
|
|
1419
|
+
skipped.push(v.name);
|
|
1420
|
+
continue;
|
|
1421
|
+
}
|
|
1422
|
+
toWrite.push({ name: v.name, placeholder: placeholderFor(v.name) });
|
|
1423
|
+
}
|
|
1424
|
+
if (toWrite.length > 0) {
|
|
1425
|
+
const lines = [];
|
|
1426
|
+
if (existing.length > 0 && !existing.endsWith("\n")) lines.push("");
|
|
1427
|
+
if (existing.length > 0) lines.push("");
|
|
1428
|
+
lines.push("# CometChat \u2014 fill in real values from https://app.cometchat.com \u2192 Your App \u2192 API & Auth Keys");
|
|
1429
|
+
for (const v of envVars) {
|
|
1430
|
+
if (presentKeys.has(v.name)) continue;
|
|
1431
|
+
const placeholder = placeholderFor(v.name);
|
|
1432
|
+
const inlineComment = v.secret ? " # secret \u2014 do not commit" : v.description ? ` # ${v.description}` : "";
|
|
1433
|
+
lines.push(`${v.name}=${placeholder}${inlineComment}`);
|
|
1434
|
+
}
|
|
1435
|
+
lines.push("");
|
|
1436
|
+
writeFileSync4(fullPath, existing + lines.join("\n"), "utf8");
|
|
1437
|
+
}
|
|
1438
|
+
const gitignoreUpdated = ensureEnvIgnored(projectRoot, fileName);
|
|
1439
|
+
return {
|
|
1440
|
+
path: fileName,
|
|
1441
|
+
written: toWrite,
|
|
1442
|
+
skipped,
|
|
1443
|
+
gitignore_updated: gitignoreUpdated
|
|
1444
|
+
};
|
|
1445
|
+
}
|
|
1446
|
+
function ensureEnvIgnored(projectRoot, envFileName) {
|
|
1447
|
+
const gitignorePath = join7(projectRoot, ".gitignore");
|
|
1448
|
+
let existing = "";
|
|
1449
|
+
if (pathExists(gitignorePath)) {
|
|
1450
|
+
try {
|
|
1451
|
+
existing = readFileSync7(gitignorePath, "utf8");
|
|
1452
|
+
} catch {
|
|
1453
|
+
existing = "";
|
|
1454
|
+
}
|
|
1455
|
+
}
|
|
1456
|
+
const lines = existing.split(/\r?\n/).map((l) => l.trim());
|
|
1457
|
+
for (const line of lines) {
|
|
1458
|
+
if (!line || line.startsWith("#")) continue;
|
|
1459
|
+
if (line === envFileName) return false;
|
|
1460
|
+
if (line === `/${envFileName}`) return false;
|
|
1461
|
+
if (line === ".env*" || line === "/.env*") return false;
|
|
1462
|
+
if (line === ".env*.local" && envFileName.endsWith(".local")) return false;
|
|
1463
|
+
if (line === ".env" && envFileName === ".env") return false;
|
|
1464
|
+
}
|
|
1465
|
+
const block = [];
|
|
1466
|
+
if (existing.length > 0 && !existing.endsWith("\n")) block.push("");
|
|
1467
|
+
if (existing.length > 0) block.push("");
|
|
1468
|
+
block.push("# CometChat \u2014 keep credentials out of source control");
|
|
1469
|
+
block.push(envFileName);
|
|
1470
|
+
block.push("");
|
|
1471
|
+
writeFileSync4(gitignorePath, existing + block.join("\n"), "utf8");
|
|
1472
|
+
return true;
|
|
1473
|
+
}
|
|
1474
|
+
|
|
1353
1475
|
// src/commands/apply.ts
|
|
1354
1476
|
function isJsonMode4(args) {
|
|
1355
1477
|
return args.flags.json === true || args.flags.json === "true";
|
|
@@ -1714,6 +1836,18 @@ async function apply(args) {
|
|
|
1714
1836
|
state_file: ".cometchat/state.json",
|
|
1715
1837
|
next_steps: (manifest.next_steps ?? []).map((s) => substitute(s, subs))
|
|
1716
1838
|
};
|
|
1839
|
+
if (manifest.env_vars.length > 0) {
|
|
1840
|
+
result.env_file = writeEnvFile({
|
|
1841
|
+
projectRoot: root,
|
|
1842
|
+
framework,
|
|
1843
|
+
envVars: result.env_vars_to_add.map((v) => ({
|
|
1844
|
+
name: v.name,
|
|
1845
|
+
required: v.required,
|
|
1846
|
+
secret: v.secret,
|
|
1847
|
+
description: manifest.env_vars.find((e) => substitute(e.name, subs) === v.name)?.description
|
|
1848
|
+
}))
|
|
1849
|
+
});
|
|
1850
|
+
}
|
|
1717
1851
|
if (embedPath !== null && entryPath !== null) {
|
|
1718
1852
|
const embedHints = embedNextSteps(framework, embedPath);
|
|
1719
1853
|
result.next_steps = [...embedHints, ...result.next_steps];
|
|
@@ -1840,12 +1974,24 @@ function printHumanReadable3(r) {
|
|
|
1840
1974
|
lines.push(" (or pass --auto-install next time to do this automatically)");
|
|
1841
1975
|
}
|
|
1842
1976
|
}
|
|
1843
|
-
if (r.
|
|
1977
|
+
if (r.env_file) {
|
|
1844
1978
|
lines.push("");
|
|
1845
|
-
|
|
1846
|
-
|
|
1847
|
-
|
|
1848
|
-
|
|
1979
|
+
if (r.env_file.written.length > 0) {
|
|
1980
|
+
lines.push(
|
|
1981
|
+
` \u2713 Wrote ${r.env_file.written.length} placeholder env var(s) to ${r.env_file.path}`
|
|
1982
|
+
);
|
|
1983
|
+
lines.push(` Open ${r.env_file.path} and replace the YOUR_*_HERE values:`);
|
|
1984
|
+
for (const v of r.env_file.written) {
|
|
1985
|
+
lines.push(` ${v.name}=${v.placeholder}`);
|
|
1986
|
+
}
|
|
1987
|
+
lines.push(` (get real values from https://app.cometchat.com \u2192 Your App \u2192 API & Auth Keys)`);
|
|
1988
|
+
} else if (r.env_vars_to_add.length > 0) {
|
|
1989
|
+
lines.push(
|
|
1990
|
+
` \u2713 All ${r.env_vars_to_add.length} env var(s) already present in ${r.env_file.path}`
|
|
1991
|
+
);
|
|
1992
|
+
}
|
|
1993
|
+
if (r.env_file.gitignore_updated) {
|
|
1994
|
+
lines.push(` + Added ${r.env_file.path} to .gitignore`);
|
|
1849
1995
|
}
|
|
1850
1996
|
}
|
|
1851
1997
|
lines.push("");
|
|
@@ -2127,7 +2273,7 @@ function printHumanReadable5(r) {
|
|
|
2127
2273
|
|
|
2128
2274
|
// src/commands/uninstall.ts
|
|
2129
2275
|
import { rmSync as rmSync2, statSync as statSync3, rmdirSync, readdirSync as readdirSync3 } from "node:fs";
|
|
2130
|
-
import { dirname as dirname5, join as
|
|
2276
|
+
import { dirname as dirname5, join as join8, resolve as resolve7 } from "node:path";
|
|
2131
2277
|
function isJsonMode7(args) {
|
|
2132
2278
|
return args.flags.json === true || args.flags.json === "true";
|
|
2133
2279
|
}
|
|
@@ -2188,7 +2334,7 @@ async function uninstall(args) {
|
|
|
2188
2334
|
const skipped = [];
|
|
2189
2335
|
const dirsToCheck = /* @__PURE__ */ new Set();
|
|
2190
2336
|
for (const file of state.files_owned) {
|
|
2191
|
-
const fullPath =
|
|
2337
|
+
const fullPath = join8(root, file);
|
|
2192
2338
|
if (!pathExists(fullPath)) {
|
|
2193
2339
|
skipped.push({ path: file, reason: "file not found" });
|
|
2194
2340
|
continue;
|
|
@@ -2442,8 +2588,8 @@ function printHumanReadable7(r) {
|
|
|
2442
2588
|
}
|
|
2443
2589
|
|
|
2444
2590
|
// src/commands/production-auth.ts
|
|
2445
|
-
import { readFileSync as
|
|
2446
|
-
import { join as
|
|
2591
|
+
import { readFileSync as readFileSync8, writeFileSync as writeFileSync5 } from "node:fs";
|
|
2592
|
+
import { join as join9, resolve as resolve9 } from "node:path";
|
|
2447
2593
|
function isJsonMode9(args) {
|
|
2448
2594
|
return args.flags.json === true || args.flags.json === "true";
|
|
2449
2595
|
}
|
|
@@ -2454,17 +2600,17 @@ function projectPath8(args) {
|
|
|
2454
2600
|
}
|
|
2455
2601
|
var SUPPORTED_FRAMEWORKS = /* @__PURE__ */ new Set(["nextjs", "react-router", "astro"]);
|
|
2456
2602
|
function productionRoot() {
|
|
2457
|
-
return
|
|
2603
|
+
return join9(findRegistryRoot(), "v6", "production");
|
|
2458
2604
|
}
|
|
2459
2605
|
function loadProductionManifest(framework) {
|
|
2460
2606
|
const root = productionRoot();
|
|
2461
|
-
const manifestPath =
|
|
2462
|
-
const content =
|
|
2607
|
+
const manifestPath = join9(root, `${framework}.template.json`);
|
|
2608
|
+
const content = readFileSync8(manifestPath, "utf8");
|
|
2463
2609
|
return JSON.parse(content);
|
|
2464
2610
|
}
|
|
2465
2611
|
function readProductionTemplate(framework, ref) {
|
|
2466
2612
|
const root = productionRoot();
|
|
2467
|
-
return
|
|
2613
|
+
return readFileSync8(join9(root, framework, ref), "utf8");
|
|
2468
2614
|
}
|
|
2469
2615
|
function findClientLoginFile(state) {
|
|
2470
2616
|
const candidates = [
|
|
@@ -2495,16 +2641,16 @@ ${indent} .catch((e: unknown) => setError(String(e)));`
|
|
|
2495
2641
|
function clientPatch(root, state) {
|
|
2496
2642
|
const relPath = findClientLoginFile(state);
|
|
2497
2643
|
if (relPath === null) return { status: "n/a" };
|
|
2498
|
-
const fullPath =
|
|
2644
|
+
const fullPath = join9(root, relPath);
|
|
2499
2645
|
let content;
|
|
2500
2646
|
try {
|
|
2501
|
-
content =
|
|
2647
|
+
content = readFileSync8(fullPath, "utf8");
|
|
2502
2648
|
} catch {
|
|
2503
2649
|
return { status: "skipped", file: relPath };
|
|
2504
2650
|
}
|
|
2505
2651
|
const next = rewriteLoginChain(content);
|
|
2506
2652
|
if (next === null) return { status: "skipped", file: relPath };
|
|
2507
|
-
|
|
2653
|
+
writeFileSync5(fullPath, next, "utf8");
|
|
2508
2654
|
return { status: "applied", file: relPath, newChecksum: sha256(next) };
|
|
2509
2655
|
}
|
|
2510
2656
|
async function productionAuth(args) {
|
|
@@ -3041,19 +3187,19 @@ function printHumanReadable9(r) {
|
|
|
3041
3187
|
}
|
|
3042
3188
|
|
|
3043
3189
|
// src/commands/features.ts
|
|
3044
|
-
import { readFileSync as
|
|
3045
|
-
import { join as
|
|
3190
|
+
import { readFileSync as readFileSync9 } from "node:fs";
|
|
3191
|
+
import { join as join10 } from "node:path";
|
|
3046
3192
|
function isJsonMode11(args) {
|
|
3047
3193
|
return args.flags.json === true || args.flags.json === "true";
|
|
3048
3194
|
}
|
|
3049
3195
|
function catalogPath() {
|
|
3050
|
-
return
|
|
3196
|
+
return join10(findRegistryRoot(), "v6", "features", "catalog.json");
|
|
3051
3197
|
}
|
|
3052
3198
|
var cachedCatalog = null;
|
|
3053
3199
|
function loadCatalog() {
|
|
3054
3200
|
if (cachedCatalog) return cachedCatalog;
|
|
3055
3201
|
const path = catalogPath();
|
|
3056
|
-
cachedCatalog = JSON.parse(
|
|
3202
|
+
cachedCatalog = JSON.parse(readFileSync9(path, "utf8"));
|
|
3057
3203
|
return cachedCatalog;
|
|
3058
3204
|
}
|
|
3059
3205
|
function nextStepsForFeature(feature) {
|
|
@@ -3066,6 +3212,7 @@ function nextStepsForFeature(feature) {
|
|
|
3066
3212
|
...feature.docs_topic ? [`For details, query the docs MCP for "${feature.docs_topic}" or visit https://www.cometchat.com/docs/ui-kit/react/${feature.docs_topic}`] : []
|
|
3067
3213
|
];
|
|
3068
3214
|
case "dashboard-toggle": {
|
|
3215
|
+
const docsUrl = feature.docs_topic ? `https://www.cometchat.com/docs/ui-kit/react/${feature.docs_topic}` : "https://www.cometchat.com/docs/ui-kit/react/extensions";
|
|
3069
3216
|
const lines = [];
|
|
3070
3217
|
if (feature.auto_wired_in_uikit) {
|
|
3071
3218
|
lines.push(
|
|
@@ -3074,8 +3221,13 @@ function nextStepsForFeature(feature) {
|
|
|
3074
3221
|
"Steps to enable:",
|
|
3075
3222
|
` 1. Go to https://app.cometchat.com and select your app`,
|
|
3076
3223
|
` 2. Navigate to: ${feature.dashboard_path ?? "Extensions \u2192 " + feature.name}`,
|
|
3224
|
+
` (this is a hint \u2014 if the dashboard UI has changed, see the canonical docs link below)`,
|
|
3077
3225
|
` 3. Toggle the feature on (and configure any required values)`,
|
|
3078
|
-
` 4. Refresh your dev server \u2014 no code changes required
|
|
3226
|
+
` 4. Refresh your dev server \u2014 no code changes required`,
|
|
3227
|
+
"",
|
|
3228
|
+
` \u{1F4D6} Canonical docs (always-current \u2014 use this if the dashboard navigation above doesn't match what you see):`,
|
|
3229
|
+
` ${docsUrl}`,
|
|
3230
|
+
` For exact, up-to-date integration steps, query the cometchat-docs MCP for "${feature.id}".`
|
|
3079
3231
|
);
|
|
3080
3232
|
} else {
|
|
3081
3233
|
lines.push(
|
|
@@ -3083,23 +3235,14 @@ function nextStepsForFeature(feature) {
|
|
|
3083
3235
|
"",
|
|
3084
3236
|
"Steps to enable:",
|
|
3085
3237
|
` 1. Go to https://app.cometchat.com \u2192 ${feature.dashboard_path ?? "Extensions \u2192 " + feature.name}, toggle on`,
|
|
3086
|
-
`
|
|
3087
|
-
`
|
|
3088
|
-
`
|
|
3089
|
-
`
|
|
3090
|
-
|
|
3091
|
-
`
|
|
3092
|
-
` .setAuthKey(AUTH_KEY)`,
|
|
3093
|
-
` .subscribePresenceForAllUsers()`,
|
|
3094
|
-
` .setExtensions([/* your extension instance here */])`,
|
|
3095
|
-
` .build();`,
|
|
3096
|
-
` CometChatUIKit.init(settings);`,
|
|
3097
|
-
` 3. Restart your dev server`
|
|
3238
|
+
` (dashboard hint \u2014 see canonical docs link below if the navigation has changed)`,
|
|
3239
|
+
` 2. Register the extension via UIKitSettingsBuilder.setExtensions([...]) in your CometChat init.`,
|
|
3240
|
+
` For the exact import path + extension class name + builder syntax, query the cometchat-docs MCP for "${feature.id}" \u2014 DO NOT invent the API from memory.`,
|
|
3241
|
+
` 3. Restart your dev server`,
|
|
3242
|
+
"",
|
|
3243
|
+
` \u{1F4D6} Canonical docs: ${docsUrl}`
|
|
3098
3244
|
);
|
|
3099
3245
|
}
|
|
3100
|
-
if (feature.docs_topic) {
|
|
3101
|
-
lines.push(` Docs: https://www.cometchat.com/docs/ui-kit/react/${feature.docs_topic}`);
|
|
3102
|
-
}
|
|
3103
3246
|
return lines;
|
|
3104
3247
|
}
|
|
3105
3248
|
case "package-install":
|
|
@@ -3377,6 +3520,14 @@ function buildIssues(args) {
|
|
|
3377
3520
|
fix: "Add the missing variables to your .env file. The chat will fail to initialize without them."
|
|
3378
3521
|
});
|
|
3379
3522
|
}
|
|
3523
|
+
if (args.envPlaceholder.length > 0) {
|
|
3524
|
+
issues.push({
|
|
3525
|
+
severity: "warning",
|
|
3526
|
+
code: "env-placeholder",
|
|
3527
|
+
message: `${args.envPlaceholder.length} env var(s) still contain YOUR_*_HERE placeholders: ${args.envPlaceholder.join(", ")}`,
|
|
3528
|
+
fix: `Open ${args.envFilePath ?? ".env"} and replace each YOUR_*_HERE value with the real one from https://app.cometchat.com \u2192 Your App \u2192 API & Auth Keys. Without this, the chat will fail to initialize at runtime.`
|
|
3529
|
+
});
|
|
3530
|
+
}
|
|
3380
3531
|
return issues;
|
|
3381
3532
|
}
|
|
3382
3533
|
async function doctor(args) {
|
|
@@ -3419,17 +3570,34 @@ async function doctor(args) {
|
|
|
3419
3570
|
} else if (expectedEnvVars[2]) {
|
|
3420
3571
|
envMissing.push(expectedEnvVars[2]);
|
|
3421
3572
|
}
|
|
3573
|
+
const envFileName = stateInfo ? envFileNameFor(stateInfo.framework) : detected.framework ? envFileNameFor(detected.framework) : null;
|
|
3574
|
+
const envFilePath = envFileName && pathExists(p(root, envFileName)) ? envFileName : null;
|
|
3575
|
+
const envPlaceholder = [];
|
|
3576
|
+
if (envFilePath) {
|
|
3577
|
+
const content = readFileOrNull(p(root, envFilePath));
|
|
3578
|
+
if (content) {
|
|
3579
|
+
const pairs = parseEnvPairs(content);
|
|
3580
|
+
for (const expected of expectedEnvVars) {
|
|
3581
|
+
const value = pairs.get(expected);
|
|
3582
|
+
if (value !== void 0 && isPlaceholder(value)) {
|
|
3583
|
+
envPlaceholder.push(expected);
|
|
3584
|
+
}
|
|
3585
|
+
}
|
|
3586
|
+
}
|
|
3587
|
+
}
|
|
3422
3588
|
const issues = buildIssues({
|
|
3423
3589
|
drift,
|
|
3424
3590
|
verify: verifyResult,
|
|
3425
3591
|
envMissing,
|
|
3592
|
+
envPlaceholder,
|
|
3593
|
+
envFilePath,
|
|
3426
3594
|
hasIntegration: stateInfo !== null
|
|
3427
3595
|
});
|
|
3428
3596
|
const errorCount = issues.filter((i) => i.severity === "error").length;
|
|
3429
3597
|
const warnCount = issues.filter((i) => i.severity === "warning").length;
|
|
3430
|
-
const
|
|
3598
|
+
const status2 = errorCount > 0 ? "issues" : warnCount > 0 ? "warnings" : "healthy";
|
|
3431
3599
|
const result = {
|
|
3432
|
-
status,
|
|
3600
|
+
status: status2,
|
|
3433
3601
|
detect: {
|
|
3434
3602
|
framework: detected.framework,
|
|
3435
3603
|
framework_version: detected.framework_version,
|
|
@@ -3453,17 +3621,19 @@ async function doctor(args) {
|
|
|
3453
3621
|
},
|
|
3454
3622
|
environment: {
|
|
3455
3623
|
env_vars_present: envPresent.filter(Boolean),
|
|
3456
|
-
env_vars_missing: envMissing
|
|
3624
|
+
env_vars_missing: envMissing,
|
|
3625
|
+
env_vars_placeholder: envPlaceholder,
|
|
3626
|
+
env_file_path: envFilePath
|
|
3457
3627
|
},
|
|
3458
3628
|
issues,
|
|
3459
|
-
summary: buildSummary(
|
|
3629
|
+
summary: buildSummary(status2, errorCount, warnCount, stateInfo !== null)
|
|
3460
3630
|
};
|
|
3461
3631
|
return outputResult7(args, result, errorCount > 0 ? 1 : 0);
|
|
3462
3632
|
}
|
|
3463
|
-
function buildSummary(
|
|
3633
|
+
function buildSummary(status2, errors, warnings, integrated) {
|
|
3464
3634
|
if (!integrated) return "No CometChat integration found. Run `cometchat apply` to get started.";
|
|
3465
|
-
if (
|
|
3466
|
-
if (
|
|
3635
|
+
if (status2 === "healthy") return "\u2713 All checks pass. Integration is healthy.";
|
|
3636
|
+
if (status2 === "warnings") return `\u26A0 ${warnings} warning(s) found. Integration works but has minor issues.`;
|
|
3467
3637
|
return `\u2717 ${errors} error(s) and ${warnings} warning(s) found. Integration may not work correctly.`;
|
|
3468
3638
|
}
|
|
3469
3639
|
function outputResult7(args, result, exitCode) {
|
|
@@ -3636,13 +3806,10 @@ async function init(args) {
|
|
|
3636
3806
|
`Run \`cometchat install\` (or pass --install next time) to install ${applyResult.deps_to_install.length} npm package(s).`
|
|
3637
3807
|
);
|
|
3638
3808
|
}
|
|
3639
|
-
|
|
3640
|
-
|
|
3641
|
-
|
|
3642
|
-
|
|
3643
|
-
result.next_actions.unshift(`Add these env vars to .env: ${envNames}`);
|
|
3644
|
-
}
|
|
3645
|
-
} catch {
|
|
3809
|
+
if (applyResult.env_file && applyResult.env_file.written.length > 0) {
|
|
3810
|
+
result.next_actions.unshift(
|
|
3811
|
+
`Open ${applyResult.env_file.path} and replace ${applyResult.env_file.written.length} YOUR_*_HERE placeholder(s) with real values from https://app.cometchat.com \u2192 Your App \u2192 API & Auth Keys.`
|
|
3812
|
+
);
|
|
3646
3813
|
}
|
|
3647
3814
|
return outputResult8(args, result, 0);
|
|
3648
3815
|
}
|
|
@@ -3685,8 +3852,8 @@ function printHumanReadable11(r) {
|
|
|
3685
3852
|
}
|
|
3686
3853
|
|
|
3687
3854
|
// src/commands/add-widget.ts
|
|
3688
|
-
import { readFileSync as
|
|
3689
|
-
import { join as
|
|
3855
|
+
import { readFileSync as readFileSync10 } from "node:fs";
|
|
3856
|
+
import { join as join11, resolve as resolve13 } from "node:path";
|
|
3690
3857
|
var SUPPORTED = /* @__PURE__ */ new Set(["reactjs", "nextjs", "react-router", "astro"]);
|
|
3691
3858
|
function isJsonMode14(args) {
|
|
3692
3859
|
return args.flags.json === true || args.flags.json === "true";
|
|
@@ -3697,16 +3864,16 @@ function projectPath12(args) {
|
|
|
3697
3864
|
return resolve13(process.cwd());
|
|
3698
3865
|
}
|
|
3699
3866
|
function widgetRoot() {
|
|
3700
|
-
return
|
|
3867
|
+
return join11(findRegistryRoot(), "v6", "widget");
|
|
3701
3868
|
}
|
|
3702
3869
|
function loadWidgetManifest(framework) {
|
|
3703
3870
|
const root = widgetRoot();
|
|
3704
|
-
const path =
|
|
3705
|
-
return JSON.parse(
|
|
3871
|
+
const path = join11(root, `${framework}.template.json`);
|
|
3872
|
+
return JSON.parse(readFileSync10(path, "utf8"));
|
|
3706
3873
|
}
|
|
3707
3874
|
function readWidgetTemplate(framework, ref) {
|
|
3708
3875
|
const root = widgetRoot();
|
|
3709
|
-
return
|
|
3876
|
+
return readFileSync10(join11(root, framework, ref), "utf8");
|
|
3710
3877
|
}
|
|
3711
3878
|
async function addWidget(args) {
|
|
3712
3879
|
const root = projectPath12(args);
|
|
@@ -3840,8 +4007,8 @@ function printHumanReadable12(r) {
|
|
|
3840
4007
|
}
|
|
3841
4008
|
|
|
3842
4009
|
// src/commands/add-user-mgmt.ts
|
|
3843
|
-
import { readFileSync as
|
|
3844
|
-
import { join as
|
|
4010
|
+
import { readFileSync as readFileSync11 } from "node:fs";
|
|
4011
|
+
import { join as join12, resolve as resolve14 } from "node:path";
|
|
3845
4012
|
var SUPPORTED2 = /* @__PURE__ */ new Set(["nextjs", "react-router", "astro"]);
|
|
3846
4013
|
function isJsonMode15(args) {
|
|
3847
4014
|
return args.flags.json === true || args.flags.json === "true";
|
|
@@ -3852,15 +4019,15 @@ function projectPath13(args) {
|
|
|
3852
4019
|
return resolve14(process.cwd());
|
|
3853
4020
|
}
|
|
3854
4021
|
function userMgmtRoot() {
|
|
3855
|
-
return
|
|
4022
|
+
return join12(findRegistryRoot(), "v6", "user-mgmt");
|
|
3856
4023
|
}
|
|
3857
4024
|
function loadManifest2(framework) {
|
|
3858
4025
|
const root = userMgmtRoot();
|
|
3859
|
-
return JSON.parse(
|
|
4026
|
+
return JSON.parse(readFileSync11(join12(root, `${framework}.template.json`), "utf8"));
|
|
3860
4027
|
}
|
|
3861
4028
|
function readTemplate(framework, ref) {
|
|
3862
4029
|
const root = userMgmtRoot();
|
|
3863
|
-
return
|
|
4030
|
+
return readFileSync11(join12(root, framework, ref), "utf8");
|
|
3864
4031
|
}
|
|
3865
4032
|
async function addUserMgmt(args) {
|
|
3866
4033
|
const root = projectPath13(args);
|
|
@@ -4017,8 +4184,8 @@ function printHumanReadable13(r) {
|
|
|
4017
4184
|
}
|
|
4018
4185
|
|
|
4019
4186
|
// src/commands/apply-feature.ts
|
|
4020
|
-
import { readFileSync as
|
|
4021
|
-
import { join as
|
|
4187
|
+
import { readFileSync as readFileSync12, writeFileSync as writeFileSync6 } from "node:fs";
|
|
4188
|
+
import { join as join13, resolve as resolve15 } from "node:path";
|
|
4022
4189
|
function isJsonMode16(args) {
|
|
4023
4190
|
return args.flags.json === true || args.flags.json === "true";
|
|
4024
4191
|
}
|
|
@@ -4028,10 +4195,10 @@ function projectPath14(args) {
|
|
|
4028
4195
|
return resolve15(process.cwd());
|
|
4029
4196
|
}
|
|
4030
4197
|
function catalogPath2() {
|
|
4031
|
-
return
|
|
4198
|
+
return join13(findRegistryRoot(), "v6", "features", "catalog.json");
|
|
4032
4199
|
}
|
|
4033
4200
|
function loadCatalog2() {
|
|
4034
|
-
return JSON.parse(
|
|
4201
|
+
return JSON.parse(readFileSync12(catalogPath2(), "utf8"));
|
|
4035
4202
|
}
|
|
4036
4203
|
function swapIdentifier(content, from, to) {
|
|
4037
4204
|
const escaped = from.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
|
|
@@ -4107,16 +4274,16 @@ async function applyFeature(args) {
|
|
|
4107
4274
|
const modified = [];
|
|
4108
4275
|
let totalReplacements = 0;
|
|
4109
4276
|
for (const relPath of state.files_owned) {
|
|
4110
|
-
const fullPath =
|
|
4277
|
+
const fullPath = join13(root, relPath);
|
|
4111
4278
|
let content;
|
|
4112
4279
|
try {
|
|
4113
|
-
content =
|
|
4280
|
+
content = readFileSync12(fullPath, "utf8");
|
|
4114
4281
|
} catch {
|
|
4115
4282
|
continue;
|
|
4116
4283
|
}
|
|
4117
4284
|
const [next, count] = swapIdentifier(content, feature.swap_from, feature.swap_to);
|
|
4118
4285
|
if (count > 0) {
|
|
4119
|
-
|
|
4286
|
+
writeFileSync6(fullPath, next, "utf8");
|
|
4120
4287
|
newChecksums[relPath] = sha256(next);
|
|
4121
4288
|
modified.push(relPath);
|
|
4122
4289
|
totalReplacements += count;
|
|
@@ -4188,6 +4355,295 @@ function printHumanReadable14(r) {
|
|
|
4188
4355
|
console.log(lines.join("\n"));
|
|
4189
4356
|
}
|
|
4190
4357
|
|
|
4358
|
+
// src/commands/status.ts
|
|
4359
|
+
import { readFileSync as readFileSync13 } from "node:fs";
|
|
4360
|
+
import { resolve as resolve16 } from "node:path";
|
|
4361
|
+
function isJsonMode17(args) {
|
|
4362
|
+
return args.flags.json === true || args.flags.json === "true";
|
|
4363
|
+
}
|
|
4364
|
+
function projectPath15(args) {
|
|
4365
|
+
const fromFlag = args.flags.path;
|
|
4366
|
+
if (typeof fromFlag === "string") return resolve16(fromFlag);
|
|
4367
|
+
return resolve16(process.cwd());
|
|
4368
|
+
}
|
|
4369
|
+
function widgetMarkerPath(state) {
|
|
4370
|
+
switch (state.framework) {
|
|
4371
|
+
case "nextjs":
|
|
4372
|
+
return state.router === "pages" ? "src/cometchat/CometChatWidget.tsx" : "src/app/cometchat/CometChatWidget.tsx";
|
|
4373
|
+
case "react-router":
|
|
4374
|
+
return "app/cometchat/CometChatWidget.tsx";
|
|
4375
|
+
case "astro":
|
|
4376
|
+
return "src/cometchat/CometChatWidget.tsx";
|
|
4377
|
+
default:
|
|
4378
|
+
return "src/cometchat/CometChatWidget.tsx";
|
|
4379
|
+
}
|
|
4380
|
+
}
|
|
4381
|
+
function productionAuthMarkerPath(state) {
|
|
4382
|
+
switch (state.framework) {
|
|
4383
|
+
case "nextjs":
|
|
4384
|
+
return state.router === "pages" ? "src/pages/api/cometchat-token.ts" : "src/app/api/cometchat-token/route.ts";
|
|
4385
|
+
case "react-router":
|
|
4386
|
+
return "app/routes/api.cometchat-token.ts";
|
|
4387
|
+
case "astro":
|
|
4388
|
+
return "src/pages/api/cometchat-token.ts";
|
|
4389
|
+
default:
|
|
4390
|
+
return "";
|
|
4391
|
+
}
|
|
4392
|
+
}
|
|
4393
|
+
function userMgmtMarkerPath(state) {
|
|
4394
|
+
switch (state.framework) {
|
|
4395
|
+
case "nextjs":
|
|
4396
|
+
return state.router === "pages" ? "src/pages/api/cometchat-user.ts" : "src/app/api/cometchat-user/route.ts";
|
|
4397
|
+
case "react-router":
|
|
4398
|
+
return "app/routes/api.cometchat-user.ts";
|
|
4399
|
+
case "astro":
|
|
4400
|
+
return "src/pages/api/cometchat-user.ts";
|
|
4401
|
+
default:
|
|
4402
|
+
return "";
|
|
4403
|
+
}
|
|
4404
|
+
}
|
|
4405
|
+
function themeFilePath(state) {
|
|
4406
|
+
switch (state.framework) {
|
|
4407
|
+
case "nextjs":
|
|
4408
|
+
return state.router === "pages" ? "src/styles/globals.css" : "src/app/globals.css";
|
|
4409
|
+
case "react-router":
|
|
4410
|
+
return "app/app.css";
|
|
4411
|
+
case "astro":
|
|
4412
|
+
return "src/cometchat/ChatApp.tsx";
|
|
4413
|
+
// theme block lives inside the React island
|
|
4414
|
+
default:
|
|
4415
|
+
return "src/index.css";
|
|
4416
|
+
}
|
|
4417
|
+
}
|
|
4418
|
+
function fileContains(root, relPath, marker) {
|
|
4419
|
+
const fullPath = p(root, relPath);
|
|
4420
|
+
if (!pathExists(fullPath)) return false;
|
|
4421
|
+
try {
|
|
4422
|
+
const content = readFileSync13(fullPath, "utf8");
|
|
4423
|
+
return content.includes(marker);
|
|
4424
|
+
} catch {
|
|
4425
|
+
return false;
|
|
4426
|
+
}
|
|
4427
|
+
}
|
|
4428
|
+
function countAuditEntries(root) {
|
|
4429
|
+
const path = p(root, AUDIT_LOG_PATH);
|
|
4430
|
+
if (!pathExists(path)) return 0;
|
|
4431
|
+
try {
|
|
4432
|
+
const content = readFileSync13(path, "utf8");
|
|
4433
|
+
const matches = content.match(/^## \d{4}-\d{2}-\d{2}T/gm);
|
|
4434
|
+
return matches ? matches.length : 0;
|
|
4435
|
+
} catch {
|
|
4436
|
+
return 0;
|
|
4437
|
+
}
|
|
4438
|
+
}
|
|
4439
|
+
async function status(args) {
|
|
4440
|
+
const root = projectPath15(args);
|
|
4441
|
+
if (!hasState(root)) {
|
|
4442
|
+
const result2 = {
|
|
4443
|
+
integrated: false,
|
|
4444
|
+
items: [],
|
|
4445
|
+
audit_log_entries: 0,
|
|
4446
|
+
audit_log_path: null,
|
|
4447
|
+
files_owned_count: 0,
|
|
4448
|
+
drift_count: 0,
|
|
4449
|
+
next_suggested: "Run `cometchat init` to scaffold a CometChat integration in this project."
|
|
4450
|
+
};
|
|
4451
|
+
return outputResult12(args, result2, 0);
|
|
4452
|
+
}
|
|
4453
|
+
const state = readState(root);
|
|
4454
|
+
if (!state) {
|
|
4455
|
+
const result2 = {
|
|
4456
|
+
integrated: false,
|
|
4457
|
+
items: [],
|
|
4458
|
+
audit_log_entries: 0,
|
|
4459
|
+
audit_log_path: null,
|
|
4460
|
+
files_owned_count: 0,
|
|
4461
|
+
drift_count: 0,
|
|
4462
|
+
next_suggested: "Could not parse .cometchat/state.json \u2014 schema mismatch?"
|
|
4463
|
+
};
|
|
4464
|
+
return outputResult12(args, result2, 1);
|
|
4465
|
+
}
|
|
4466
|
+
const items = [];
|
|
4467
|
+
items.push({
|
|
4468
|
+
step: 2,
|
|
4469
|
+
state: "done",
|
|
4470
|
+
label: "Base integration",
|
|
4471
|
+
detail: `experience ${state.experience} (${state.experience_slug}) on ${state.framework}${state.router ? ` (${state.router} router)` : ""}`
|
|
4472
|
+
});
|
|
4473
|
+
for (const feature of state.applied_features ?? []) {
|
|
4474
|
+
items.push({
|
|
4475
|
+
step: 4,
|
|
4476
|
+
state: "done",
|
|
4477
|
+
label: "Feature applied",
|
|
4478
|
+
detail: feature
|
|
4479
|
+
});
|
|
4480
|
+
}
|
|
4481
|
+
const widgetPath = widgetMarkerPath(state);
|
|
4482
|
+
if (widgetPath && pathExists(p(root, widgetPath))) {
|
|
4483
|
+
items.push({
|
|
4484
|
+
step: 4,
|
|
4485
|
+
state: "done",
|
|
4486
|
+
label: "Floating chat widget",
|
|
4487
|
+
detail: widgetPath
|
|
4488
|
+
});
|
|
4489
|
+
} else {
|
|
4490
|
+
items.push({
|
|
4491
|
+
step: 4,
|
|
4492
|
+
state: "todo",
|
|
4493
|
+
label: "Floating chat widget",
|
|
4494
|
+
detail: "not added",
|
|
4495
|
+
next_command: "cometchat add-widget"
|
|
4496
|
+
});
|
|
4497
|
+
}
|
|
4498
|
+
const userMgmtPath = userMgmtMarkerPath(state);
|
|
4499
|
+
if (state.framework === "reactjs") {
|
|
4500
|
+
items.push({
|
|
4501
|
+
step: 4,
|
|
4502
|
+
state: "skipped",
|
|
4503
|
+
label: "Server user management",
|
|
4504
|
+
detail: "reactjs has no built-in server (BYO backend)"
|
|
4505
|
+
});
|
|
4506
|
+
} else if (userMgmtPath && pathExists(p(root, userMgmtPath))) {
|
|
4507
|
+
items.push({
|
|
4508
|
+
step: 4,
|
|
4509
|
+
state: "done",
|
|
4510
|
+
label: "Server user management",
|
|
4511
|
+
detail: userMgmtPath
|
|
4512
|
+
});
|
|
4513
|
+
} else {
|
|
4514
|
+
items.push({
|
|
4515
|
+
step: 4,
|
|
4516
|
+
state: "todo",
|
|
4517
|
+
label: "Server user management",
|
|
4518
|
+
detail: "no /api/cometchat-user endpoint",
|
|
4519
|
+
next_command: "cometchat add-user-mgmt"
|
|
4520
|
+
});
|
|
4521
|
+
}
|
|
4522
|
+
const prodAuthPath = productionAuthMarkerPath(state);
|
|
4523
|
+
if (state.framework === "reactjs") {
|
|
4524
|
+
items.push({
|
|
4525
|
+
step: 5,
|
|
4526
|
+
state: "skipped",
|
|
4527
|
+
label: "Production auth",
|
|
4528
|
+
detail: "reactjs has no built-in server (BYO backend)"
|
|
4529
|
+
});
|
|
4530
|
+
} else if (state.credentials_source === "token-endpoint" || prodAuthPath && pathExists(p(root, prodAuthPath))) {
|
|
4531
|
+
items.push({
|
|
4532
|
+
step: 5,
|
|
4533
|
+
state: "done",
|
|
4534
|
+
label: "Production auth",
|
|
4535
|
+
detail: prodAuthPath || "server-side token endpoint"
|
|
4536
|
+
});
|
|
4537
|
+
} else {
|
|
4538
|
+
items.push({
|
|
4539
|
+
step: 5,
|
|
4540
|
+
state: "todo",
|
|
4541
|
+
label: "Production auth",
|
|
4542
|
+
detail: "still on dev Auth Key (insecure for prod)",
|
|
4543
|
+
next_command: "cometchat production-auth"
|
|
4544
|
+
});
|
|
4545
|
+
}
|
|
4546
|
+
const drift = detectDrift(root, state);
|
|
4547
|
+
const customizationCount = drift.modified_files.length;
|
|
4548
|
+
items.push({
|
|
4549
|
+
step: 5,
|
|
4550
|
+
state: customizationCount > 0 ? "done" : "todo",
|
|
4551
|
+
label: "Customizations",
|
|
4552
|
+
detail: customizationCount > 0 ? `${customizationCount} file modification(s) outside templates` : "0 modifications (still on default templates)",
|
|
4553
|
+
next_command: customizationCount > 0 ? void 0 : void 0
|
|
4554
|
+
});
|
|
4555
|
+
const themePath = themeFilePath(state);
|
|
4556
|
+
if (themePath && fileContains(root, themePath, "CometChat theme overrides")) {
|
|
4557
|
+
items.push({
|
|
4558
|
+
step: 7,
|
|
4559
|
+
state: "done",
|
|
4560
|
+
label: "Theme",
|
|
4561
|
+
detail: `applied to ${themePath}`
|
|
4562
|
+
});
|
|
4563
|
+
} else {
|
|
4564
|
+
items.push({
|
|
4565
|
+
step: 7,
|
|
4566
|
+
state: "todo",
|
|
4567
|
+
label: "Theme",
|
|
4568
|
+
detail: "no overrides applied (still on UI Kit defaults)",
|
|
4569
|
+
next_command: "cometchat apply-theme --preset slack"
|
|
4570
|
+
});
|
|
4571
|
+
}
|
|
4572
|
+
let nextSuggested;
|
|
4573
|
+
const todoItems = items.filter((i) => i.state === "todo" && i.next_command);
|
|
4574
|
+
const prodAuthTodo = todoItems.find((i) => i.label === "Production auth");
|
|
4575
|
+
const widgetTodo = todoItems.find((i) => i.label === "Floating chat widget");
|
|
4576
|
+
const themeTodo = todoItems.find((i) => i.label === "Theme");
|
|
4577
|
+
if (prodAuthTodo) {
|
|
4578
|
+
nextSuggested = `Run \`${prodAuthTodo.next_command}\` before deploying to production \u2014 your dev Auth Key is currently exposed to the browser.`;
|
|
4579
|
+
} else if (themeTodo) {
|
|
4580
|
+
nextSuggested = `Run \`${themeTodo.next_command}\` to brand the chat UI (or pick a different preset: whatsapp, imessage, discord, notion).`;
|
|
4581
|
+
} else if (widgetTodo) {
|
|
4582
|
+
nextSuggested = `Run \`${widgetTodo.next_command}\` to add a floating chat overlay.`;
|
|
4583
|
+
} else if (todoItems.length === 0) {
|
|
4584
|
+
nextSuggested = "Looks complete! Run `cometchat verify` for a final correctness check.";
|
|
4585
|
+
} else {
|
|
4586
|
+
nextSuggested = `Run \`/cometchat\` to open the iteration menu and pick what's next.`;
|
|
4587
|
+
}
|
|
4588
|
+
const result = {
|
|
4589
|
+
integrated: true,
|
|
4590
|
+
framework: state.framework,
|
|
4591
|
+
framework_version: state.framework_version,
|
|
4592
|
+
experience: state.experience,
|
|
4593
|
+
experience_slug: state.experience_slug,
|
|
4594
|
+
router: state.router,
|
|
4595
|
+
items,
|
|
4596
|
+
audit_log_entries: countAuditEntries(root),
|
|
4597
|
+
audit_log_path: pathExists(p(root, AUDIT_LOG_PATH)) ? AUDIT_LOG_PATH : null,
|
|
4598
|
+
files_owned_count: state.files_owned.length,
|
|
4599
|
+
drift_count: drift.modified_files.length,
|
|
4600
|
+
next_suggested: nextSuggested
|
|
4601
|
+
};
|
|
4602
|
+
return outputResult12(args, result, 0);
|
|
4603
|
+
}
|
|
4604
|
+
function outputResult12(args, result, exitCode) {
|
|
4605
|
+
if (isJsonMode17(args)) {
|
|
4606
|
+
console.log(JSON.stringify(result, null, 2));
|
|
4607
|
+
return exitCode;
|
|
4608
|
+
}
|
|
4609
|
+
printHumanReadable15(result);
|
|
4610
|
+
return exitCode;
|
|
4611
|
+
}
|
|
4612
|
+
function printHumanReadable15(r) {
|
|
4613
|
+
const lines = [];
|
|
4614
|
+
lines.push("");
|
|
4615
|
+
if (!r.integrated) {
|
|
4616
|
+
lines.push(" CometChat React integration \u2014 not yet started");
|
|
4617
|
+
lines.push("");
|
|
4618
|
+
if (r.next_suggested) lines.push(` \u2192 ${r.next_suggested}`);
|
|
4619
|
+
lines.push("");
|
|
4620
|
+
console.log(lines.join("\n"));
|
|
4621
|
+
return;
|
|
4622
|
+
}
|
|
4623
|
+
lines.push(` CometChat React integration \u2014 your progress`);
|
|
4624
|
+
lines.push("");
|
|
4625
|
+
for (const item of r.items) {
|
|
4626
|
+
const icon = item.state === "done" ? "\u2713" : item.state === "skipped" ? "\u2014" : "\u25CB";
|
|
4627
|
+
const stepCol = `Step ${item.step}:`.padEnd(8);
|
|
4628
|
+
const labelCol = item.label.padEnd(28);
|
|
4629
|
+
const detail = item.detail ? ` (${item.detail})` : "";
|
|
4630
|
+
lines.push(` ${icon} ${stepCol} ${labelCol}${detail}`);
|
|
4631
|
+
}
|
|
4632
|
+
lines.push("");
|
|
4633
|
+
lines.push(
|
|
4634
|
+
` Audit log: ${r.audit_log_path ?? "none"}` + (r.audit_log_path ? ` (${r.audit_log_entries} entr${r.audit_log_entries === 1 ? "y" : "ies"})` : "")
|
|
4635
|
+
);
|
|
4636
|
+
lines.push(` Files owned: ${r.files_owned_count}`);
|
|
4637
|
+
lines.push(` Drift: ${r.drift_count > 0 ? `${r.drift_count} customized file(s)` : "none"}`);
|
|
4638
|
+
if (r.next_suggested) {
|
|
4639
|
+
lines.push("");
|
|
4640
|
+
lines.push(" Next suggested step:");
|
|
4641
|
+
lines.push(` \u2192 ${r.next_suggested}`);
|
|
4642
|
+
}
|
|
4643
|
+
lines.push("");
|
|
4644
|
+
console.log(lines.join("\n"));
|
|
4645
|
+
}
|
|
4646
|
+
|
|
4191
4647
|
// src/index.ts
|
|
4192
4648
|
var VERSION = "0.0.1";
|
|
4193
4649
|
var HELP = `
|
|
@@ -4273,6 +4729,12 @@ Commands:
|
|
|
4273
4729
|
for production sign-up flows. Currently nextjs,
|
|
4274
4730
|
react-router, and astro.
|
|
4275
4731
|
|
|
4732
|
+
status Journey-shaped progress summary. Aggregates state +
|
|
4733
|
+
applied_features + file markers into a checklist
|
|
4734
|
+
that mirrors the React UI Kit Integration Journey
|
|
4735
|
+
(base, features, widget, prod-auth, theme, etc.)
|
|
4736
|
+
and suggests the highest-leverage next action.
|
|
4737
|
+
|
|
4276
4738
|
apply-feature <id> Apply a component-swap feature on top of the
|
|
4277
4739
|
current integration (e.g.
|
|
4278
4740
|
\`apply-feature rich-text-formatting\` swaps
|
|
@@ -4373,6 +4835,8 @@ async function run(argv) {
|
|
|
4373
4835
|
return addUserMgmt(args);
|
|
4374
4836
|
case "apply-feature":
|
|
4375
4837
|
return applyFeature(args);
|
|
4838
|
+
case "status":
|
|
4839
|
+
return status(args);
|
|
4376
4840
|
default:
|
|
4377
4841
|
console.error(`Unknown command: ${args.command}`);
|
|
4378
4842
|
console.error("Run `cometchat --help` for usage.");
|
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
"$schema": "https://json-schema.org/draft/2020-12/schema",
|
|
3
3
|
"version": "1.0.0",
|
|
4
4
|
"sdk_compatibility": ">=6.0.0 <7.0.0",
|
|
5
|
-
"description": "Catalog of CometChat features available in the React UI Kit. Categorized by what work is needed to enable each one.",
|
|
5
|
+
"description": "Catalog of CometChat features available in the React UI Kit. Categorized by what work is needed to enable each one. NOTE: this catalog stores OUR taxonomy (default vs dashboard-toggle vs package-install vs component-swap) plus a `dashboard_path` HINT for navigation. The hint is short and intentionally fragile — the canonical source is always the docs URL constructed from `docs_topic`. Agents must query the cometchat-docs MCP at runtime for current dashboard navigation, prop signatures, builder methods, and SDK reference. This catalog is for routing, not for SDK reference.",
|
|
6
6
|
"feature_types": {
|
|
7
7
|
"default": "Already enabled by default in the UI Kit components your integration uses. Zero code changes needed — the skill just shows you which component renders it.",
|
|
8
8
|
"dashboard-toggle": "Requires flipping a toggle in the CometChat Dashboard at https://app.cometchat.com. Some have their UI decorator auto-attached by the UI Kit (auto_wired_in_uikit: true) — the dashboard flip is the only thing needed. Others additionally require passing the extension to UIKitSettingsBuilder.setExtensions([...]) before init.",
|
package/package.json
CHANGED
|
@@ -1,11 +1,11 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@cometchat/skills-cli",
|
|
3
|
-
"version": "2.0.
|
|
3
|
+
"version": "2.0.1",
|
|
4
4
|
"description": "CLI for the CometChat skills v2 architecture — detect, view, apply, verify CometChat integrations in React projects.",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"license": "MIT",
|
|
7
7
|
"bin": {
|
|
8
|
-
"cometchat": "
|
|
8
|
+
"cometchat": "bin/cometchat.mjs"
|
|
9
9
|
},
|
|
10
10
|
"files": [
|
|
11
11
|
"bin/",
|