@synity/bitrix-skills 1.3.7 → 1.3.9
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/CHANGELOG.md +14 -0
- package/dist/cli.js +93 -15
- package/package.json +1 -1
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,19 @@
|
|
|
1
1
|
# Changelog
|
|
2
2
|
|
|
3
|
+
## 1.3.9
|
|
4
|
+
|
|
5
|
+
### Patch Changes
|
|
6
|
+
|
|
7
|
+
- feat(license): auto-detect UUID tokens (from OTP email flow) — pass as `token` field instead of `key`
|
|
8
|
+
|
|
9
|
+
## 1.3.8
|
|
10
|
+
|
|
11
|
+
### Patch Changes
|
|
12
|
+
|
|
13
|
+
- fix(list): global features now show correct [installed] status by checking ~/.claude/skills/<name>/ on disk instead of project manifest
|
|
14
|
+
|
|
15
|
+
fix(install): add --all flag + generic install handler for bx, bx-crm, bx-calendar global skills
|
|
16
|
+
|
|
3
17
|
## 1.3.7
|
|
4
18
|
|
|
5
19
|
### Patch Changes
|
package/dist/cli.js
CHANGED
|
@@ -944,11 +944,15 @@ import { createRequire } from "module";
|
|
|
944
944
|
|
|
945
945
|
// src/commands/install.ts
|
|
946
946
|
init_esm_shims();
|
|
947
|
+
init_fs_safety();
|
|
947
948
|
import { Command, Option } from "clipanion";
|
|
948
949
|
import chalk from "chalk";
|
|
949
950
|
import { existsSync as existsSync4 } from "fs";
|
|
951
|
+
import { access as access4, copyFile as copyFile3, mkdir as mkdir4, readdir as readdir2 } from "fs/promises";
|
|
950
952
|
import { createInterface } from "readline";
|
|
951
|
-
import { join as join4, relative as relative2 } from "path";
|
|
953
|
+
import { dirname as dirname3, join as join4, relative as relative2, resolve as resolve2 } from "path";
|
|
954
|
+
import { homedir as homedir2 } from "os";
|
|
955
|
+
import { fileURLToPath as fileURLToPath5 } from "url";
|
|
952
956
|
|
|
953
957
|
// src/lib/feature-registry.ts
|
|
954
958
|
init_esm_shims();
|
|
@@ -996,15 +1000,18 @@ function listFeatures(featuresDir) {
|
|
|
996
1000
|
// src/lib/license.ts
|
|
997
1001
|
init_esm_shims();
|
|
998
1002
|
var LICENSE_WORKER_URL = "https://license-gate.synity.workers.dev";
|
|
1003
|
+
var UUID_RE = /^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$/i;
|
|
999
1004
|
async function verifyLicense(key) {
|
|
1000
1005
|
if (!key || key.trim() === "") {
|
|
1001
1006
|
return { ok: true, tier: 0 };
|
|
1002
1007
|
}
|
|
1008
|
+
const trimmed = key.trim();
|
|
1009
|
+
const isToken = UUID_RE.test(trimmed);
|
|
1003
1010
|
try {
|
|
1004
1011
|
const res = await fetch(`${LICENSE_WORKER_URL}/verify`, {
|
|
1005
1012
|
method: "POST",
|
|
1006
1013
|
headers: { "Content-Type": "application/json" },
|
|
1007
|
-
body: JSON.stringify({
|
|
1014
|
+
body: JSON.stringify(isToken ? { token: trimmed } : { key: trimmed }),
|
|
1008
1015
|
signal: AbortSignal.timeout(8e3)
|
|
1009
1016
|
});
|
|
1010
1017
|
if (!res.ok) {
|
|
@@ -1046,11 +1053,11 @@ function computeChecksum(filepath) {
|
|
|
1046
1053
|
|
|
1047
1054
|
// src/commands/install.ts
|
|
1048
1055
|
function promptKey() {
|
|
1049
|
-
return new Promise((
|
|
1056
|
+
return new Promise((resolve4) => {
|
|
1050
1057
|
const rl = createInterface({ input: process.stdin, output: process.stdout });
|
|
1051
1058
|
rl.question(chalk.cyan("License key (Enter to skip \u2014 free tier only): "), (answer) => {
|
|
1052
1059
|
rl.close();
|
|
1053
|
-
|
|
1060
|
+
resolve4(answer.trim());
|
|
1054
1061
|
});
|
|
1055
1062
|
});
|
|
1056
1063
|
}
|
|
@@ -1096,6 +1103,63 @@ async function installBxTask(cwd) {
|
|
|
1096
1103
|
return { ok: false, message: `bx-task: ${err.message}` };
|
|
1097
1104
|
}
|
|
1098
1105
|
}
|
|
1106
|
+
async function getFeatureAssetsDir(featureName) {
|
|
1107
|
+
const here = dirname3(fileURLToPath5(import.meta.url));
|
|
1108
|
+
const candidates = [
|
|
1109
|
+
// dist/cli.js context (inlined): ../src/features/<name>/assets
|
|
1110
|
+
resolve2(here, `../src/features/${featureName}/assets`),
|
|
1111
|
+
// dist/features/<name>/ context: ../../../src/features/<name>/assets
|
|
1112
|
+
resolve2(here, `../../../src/features/${featureName}/assets`),
|
|
1113
|
+
// dev (running from src/)
|
|
1114
|
+
resolve2(here, `../features/${featureName}/assets`)
|
|
1115
|
+
];
|
|
1116
|
+
for (const c of candidates) {
|
|
1117
|
+
try {
|
|
1118
|
+
await access4(c);
|
|
1119
|
+
return c;
|
|
1120
|
+
} catch {
|
|
1121
|
+
}
|
|
1122
|
+
}
|
|
1123
|
+
return candidates[0];
|
|
1124
|
+
}
|
|
1125
|
+
async function copyDirRecursive(srcDir, destDir, skillBase, installedFiles, onConflict) {
|
|
1126
|
+
await mkdir4(destDir, { recursive: true });
|
|
1127
|
+
const entries = await readdir2(srcDir, { withFileTypes: true });
|
|
1128
|
+
for (const entry of entries) {
|
|
1129
|
+
const src = join4(srcDir, entry.name);
|
|
1130
|
+
const dest = join4(destDir, entry.name);
|
|
1131
|
+
if (entry.isDirectory()) {
|
|
1132
|
+
await copyDirRecursive(src, dest, skillBase, installedFiles, onConflict);
|
|
1133
|
+
continue;
|
|
1134
|
+
}
|
|
1135
|
+
assertContainedIn(dest, skillBase, dest);
|
|
1136
|
+
await assertNotSymlink(dest);
|
|
1137
|
+
try {
|
|
1138
|
+
await access4(dest);
|
|
1139
|
+
if (onConflict === "skip") continue;
|
|
1140
|
+
} catch {
|
|
1141
|
+
}
|
|
1142
|
+
await copyFile3(src, dest);
|
|
1143
|
+
installedFiles.push(dest);
|
|
1144
|
+
}
|
|
1145
|
+
}
|
|
1146
|
+
async function installGlobalSkill(featureName) {
|
|
1147
|
+
try {
|
|
1148
|
+
const skillBase = resolve2(homedir2(), ".claude", "skills");
|
|
1149
|
+
const dest = resolve2(skillBase, featureName);
|
|
1150
|
+
const assetsDir = await getFeatureAssetsDir(featureName);
|
|
1151
|
+
const installedFiles = [];
|
|
1152
|
+
await copyDirRecursive(assetsDir, dest, skillBase, installedFiles, "overwrite");
|
|
1153
|
+
return {
|
|
1154
|
+
ok: true,
|
|
1155
|
+
message: `${featureName}: ${installedFiles.length} files installed`,
|
|
1156
|
+
installPath: dest,
|
|
1157
|
+
installedAbsPaths: installedFiles
|
|
1158
|
+
};
|
|
1159
|
+
} catch (err) {
|
|
1160
|
+
return { ok: false, message: `${featureName}: ${err.message}` };
|
|
1161
|
+
}
|
|
1162
|
+
}
|
|
1099
1163
|
function upsertFeature(manifest, entry) {
|
|
1100
1164
|
const idx = manifest.features.findIndex((f) => f.name === entry.name);
|
|
1101
1165
|
const features = [...manifest.features];
|
|
@@ -1122,6 +1186,7 @@ var InstallCommand = class extends Command {
|
|
|
1122
1186
|
]
|
|
1123
1187
|
});
|
|
1124
1188
|
key = Option.String("--key", { description: "License key to unlock paid tier features" });
|
|
1189
|
+
all = Option.Boolean("--all", false, { description: "Install all available features" });
|
|
1125
1190
|
featuresFlag = Option.String("--features", { description: "Comma-separated feature names" });
|
|
1126
1191
|
featureArgs = Option.Rest({ required: 0 });
|
|
1127
1192
|
async execute() {
|
|
@@ -1207,10 +1272,15 @@ Installing ${chalk.bold(name)}...
|
|
|
1207
1272
|
ok = r.ok;
|
|
1208
1273
|
message = r.message;
|
|
1209
1274
|
if (r.installPath) {
|
|
1210
|
-
const { homedir: homedir2 } = await import("os");
|
|
1211
1275
|
installPath = join4(homedir2(), ".claude", "skills", "bx-task");
|
|
1212
1276
|
}
|
|
1213
1277
|
installedAbsPaths = r.installedAbsPaths ?? [];
|
|
1278
|
+
} else if (featureInfo.target === "global") {
|
|
1279
|
+
const r = await installGlobalSkill(name);
|
|
1280
|
+
ok = r.ok;
|
|
1281
|
+
message = r.message;
|
|
1282
|
+
if (r.installPath) installPath = r.installPath;
|
|
1283
|
+
installedAbsPaths = r.installedAbsPaths ?? [];
|
|
1214
1284
|
} else {
|
|
1215
1285
|
this.context.stderr.write(chalk.yellow(` ! No install handler for feature: ${name}
|
|
1216
1286
|
`));
|
|
@@ -1321,6 +1391,15 @@ Uninstalling ${chalk2.bold(name)}...
|
|
|
1321
1391
|
init_esm_shims();
|
|
1322
1392
|
import { Command as Command3 } from "clipanion";
|
|
1323
1393
|
import chalk3 from "chalk";
|
|
1394
|
+
import { existsSync as existsSync5 } from "fs";
|
|
1395
|
+
import { resolve as resolve3 } from "path";
|
|
1396
|
+
import { homedir as homedir3 } from "os";
|
|
1397
|
+
function isInstalled(f, manifest) {
|
|
1398
|
+
if (f.target === "global") {
|
|
1399
|
+
return existsSync5(resolve3(homedir3(), ".claude", "skills", f.name));
|
|
1400
|
+
}
|
|
1401
|
+
return !!manifest?.features.find((e) => e.name === f.name);
|
|
1402
|
+
}
|
|
1324
1403
|
var ListCommand = class extends Command3 {
|
|
1325
1404
|
static paths = [["list"]];
|
|
1326
1405
|
static usage = Command3.Usage({
|
|
@@ -1329,20 +1408,19 @@ var ListCommand = class extends Command3 {
|
|
|
1329
1408
|
async execute() {
|
|
1330
1409
|
const features = listFeatures();
|
|
1331
1410
|
const manifest = readManifest(process.cwd());
|
|
1332
|
-
const installed = new Map(manifest?.features.map((f) => [f.name, f]) ?? []);
|
|
1333
1411
|
if (features.length === 0) {
|
|
1334
1412
|
this.context.stdout.write(chalk3.yellow("No features found.\n"));
|
|
1335
1413
|
return 0;
|
|
1336
1414
|
}
|
|
1337
1415
|
this.context.stdout.write("\nAvailable features:\n");
|
|
1338
1416
|
for (const f of features) {
|
|
1339
|
-
const
|
|
1340
|
-
const check =
|
|
1417
|
+
const installed = isInstalled(f, manifest);
|
|
1418
|
+
const check = installed ? chalk3.green("\u2713") : chalk3.gray("\u25CB");
|
|
1341
1419
|
const name = chalk3.bold(f.name.padEnd(12));
|
|
1342
1420
|
const ver = chalk3.cyan(f.version.padEnd(14));
|
|
1343
1421
|
const target = chalk3.gray(f.target.padEnd(8));
|
|
1344
1422
|
const desc = f.description;
|
|
1345
|
-
const status =
|
|
1423
|
+
const status = installed ? chalk3.green("[installed]") : chalk3.gray("[not installed]");
|
|
1346
1424
|
this.context.stdout.write(` ${check} ${name} ${ver} ${target} ${desc} ${status}
|
|
1347
1425
|
`);
|
|
1348
1426
|
}
|
|
@@ -1354,7 +1432,7 @@ var ListCommand = class extends Command3 {
|
|
|
1354
1432
|
init_esm_shims();
|
|
1355
1433
|
import { Command as Command4 } from "clipanion";
|
|
1356
1434
|
import chalk4 from "chalk";
|
|
1357
|
-
import { existsSync as
|
|
1435
|
+
import { existsSync as existsSync6 } from "fs";
|
|
1358
1436
|
import { join as join5 } from "path";
|
|
1359
1437
|
var VerifyCommand = class extends Command4 {
|
|
1360
1438
|
static paths = [["verify"]];
|
|
@@ -1378,7 +1456,7 @@ var VerifyCommand = class extends Command4 {
|
|
|
1378
1456
|
`);
|
|
1379
1457
|
this.context.stdout.write(chalk4.gray(` install path: ${feature.installPath}
|
|
1380
1458
|
`));
|
|
1381
|
-
if (!
|
|
1459
|
+
if (!existsSync6(feature.installPath)) {
|
|
1382
1460
|
this.context.stderr.write(chalk4.red(` \u2717 install path missing: ${feature.installPath}
|
|
1383
1461
|
`));
|
|
1384
1462
|
anyMismatch = true;
|
|
@@ -1391,7 +1469,7 @@ var VerifyCommand = class extends Command4 {
|
|
|
1391
1469
|
}
|
|
1392
1470
|
for (const [rel, expectedHash] of Object.entries(stored)) {
|
|
1393
1471
|
const absPath = join5(feature.installPath, rel);
|
|
1394
|
-
if (!
|
|
1472
|
+
if (!existsSync6(absPath)) {
|
|
1395
1473
|
this.context.stderr.write(chalk4.red(` \u2717 missing: ${rel}
|
|
1396
1474
|
`));
|
|
1397
1475
|
anyMismatch = true;
|
|
@@ -1430,7 +1508,7 @@ var VerifyCommand = class extends Command4 {
|
|
|
1430
1508
|
init_esm_shims();
|
|
1431
1509
|
import { Command as Command5 } from "clipanion";
|
|
1432
1510
|
import chalk5 from "chalk";
|
|
1433
|
-
import { existsSync as
|
|
1511
|
+
import { existsSync as existsSync7 } from "fs";
|
|
1434
1512
|
import { relative as relative3 } from "path";
|
|
1435
1513
|
var UpdateCommand = class extends Command5 {
|
|
1436
1514
|
static paths = [["update"]];
|
|
@@ -1478,7 +1556,7 @@ var UpdateCommand = class extends Command5 {
|
|
|
1478
1556
|
const { buildDestMap: buildDestMap2 } = await Promise.resolve().then(() => (init_dest_map(), dest_map_exports));
|
|
1479
1557
|
const assetManifest = await loadManifest2();
|
|
1480
1558
|
const dests = buildDestMap2(assetManifest, cwd);
|
|
1481
|
-
installedAbsPaths = dests.map((d) => d.destAbs).filter((p) =>
|
|
1559
|
+
installedAbsPaths = dests.map((d) => d.destAbs).filter((p) => existsSync7(p));
|
|
1482
1560
|
} catch {
|
|
1483
1561
|
}
|
|
1484
1562
|
} else if (feature.name === "bx-task") {
|
|
@@ -1507,7 +1585,7 @@ var UpdateCommand = class extends Command5 {
|
|
|
1507
1585
|
const checksums = {};
|
|
1508
1586
|
for (const absPath of installedAbsPaths) {
|
|
1509
1587
|
try {
|
|
1510
|
-
if (
|
|
1588
|
+
if (existsSync7(absPath)) {
|
|
1511
1589
|
const rel = relative3(feature.installPath, absPath);
|
|
1512
1590
|
checksums[rel] = computeChecksum(absPath);
|
|
1513
1591
|
}
|