@llmist/cli 9.2.0 → 9.3.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/dist/cli.js CHANGED
@@ -79,7 +79,7 @@ import { Command, InvalidArgumentError as InvalidArgumentError2 } from "commande
79
79
  // package.json
80
80
  var package_default = {
81
81
  name: "@llmist/cli",
82
- version: "9.2.0",
82
+ version: "9.3.0",
83
83
  description: "CLI for llmist - run LLM agents from the command line",
84
84
  type: "module",
85
85
  main: "dist/cli.js",
@@ -94,6 +94,7 @@ var package_default = {
94
94
  clean: "rimraf dist",
95
95
  postinstall: "node scripts/postinstall.js"
96
96
  },
97
+ homepage: "https://llmist.dev",
97
98
  repository: {
98
99
  type: "git",
99
100
  url: "https://github.com/zbigniewsobiecki/llmist.git",
@@ -931,49 +932,71 @@ function parseGadgetSpecifier(specifier) {
931
932
  let baseUrl;
932
933
  let ref;
933
934
  let preset;
935
+ let gadgetName;
936
+ const extractGadgetName = (str) => {
937
+ const match = str.match(/^(.*)\/([A-Z][a-zA-Z0-9]*)$/);
938
+ if (match) {
939
+ return { rest: match[1], gadgetName: match[2] };
940
+ }
941
+ return { rest: str };
942
+ };
934
943
  if (url.includes("#")) {
935
944
  const hashIndex = url.indexOf("#");
936
945
  baseUrl = url.slice(0, hashIndex);
937
- const refAndPreset = url.slice(hashIndex + 1);
938
- if (refAndPreset.includes(":")) {
939
- const colonIndex = refAndPreset.indexOf(":");
940
- ref = refAndPreset.slice(0, colonIndex);
941
- preset = refAndPreset.slice(colonIndex + 1);
946
+ let refAndRest = url.slice(hashIndex + 1);
947
+ const gadgetResult = extractGadgetName(refAndRest);
948
+ refAndRest = gadgetResult.rest;
949
+ gadgetName = gadgetResult.gadgetName;
950
+ if (refAndRest.includes(":")) {
951
+ const colonIndex = refAndRest.indexOf(":");
952
+ ref = refAndRest.slice(0, colonIndex);
953
+ preset = refAndRest.slice(colonIndex + 1);
942
954
  } else {
943
- ref = refAndPreset;
955
+ ref = refAndRest;
944
956
  }
945
957
  } else {
946
958
  const gitExtIndex = url.indexOf(".git");
947
959
  if (gitExtIndex !== -1) {
948
- const afterGit = url.slice(gitExtIndex + 4);
960
+ let afterGit = url.slice(gitExtIndex + 4);
961
+ baseUrl = url.slice(0, gitExtIndex + 4);
962
+ const gadgetResult = extractGadgetName(afterGit);
963
+ afterGit = gadgetResult.rest;
964
+ gadgetName = gadgetResult.gadgetName;
949
965
  if (afterGit.startsWith(":")) {
950
- baseUrl = url.slice(0, gitExtIndex + 4);
951
966
  preset = afterGit.slice(1);
952
- } else {
953
- baseUrl = url;
954
967
  }
955
968
  } else {
956
- baseUrl = url;
969
+ const gadgetResult = extractGadgetName(url);
970
+ baseUrl = gadgetResult.rest;
971
+ gadgetName = gadgetResult.gadgetName;
957
972
  }
958
973
  }
959
974
  return {
960
975
  type: "git",
961
976
  package: baseUrl,
962
977
  version: ref,
963
- preset
978
+ preset,
979
+ gadgetName
964
980
  };
965
981
  }
966
- const npmMatch = specifier.match(
967
- /^(@?[a-z0-9][\w.-]*)(?:@([\w.-]+))?(?::([a-z]+))?(?:\/(\w+))?$/i
982
+ let npmSpecifier = specifier;
983
+ let npmGadgetName;
984
+ const gadgetMatch = specifier.match(/^(.+)\/([A-Z][a-zA-Z0-9]*)$/);
985
+ if (gadgetMatch) {
986
+ npmSpecifier = gadgetMatch[1];
987
+ npmGadgetName = gadgetMatch[2];
988
+ }
989
+ const npmMatch = npmSpecifier.match(
990
+ /^(@[a-z0-9][\w.-]*\/[a-z0-9][\w.-]*|[a-z0-9][\w.-]*)(?:@([\w.-]+))?(?::([a-z]+))?$/i
968
991
  );
969
992
  if (npmMatch) {
970
- const [, pkg, version, preset, gadgetName] = npmMatch;
993
+ const [, pkg, version, preset] = npmMatch;
971
994
  return {
972
995
  type: "npm",
973
996
  package: pkg,
974
997
  version,
975
998
  preset,
976
- gadgetName
999
+ gadgetName: npmGadgetName
977
1000
  };
978
1001
  }
979
1002
  return null;
@@ -1227,6 +1250,14 @@ function expandHomePath(input) {
1227
1250
  }
1228
1251
  return path5.join(home, input.slice(1));
1229
1252
  }
1253
+ function parseLocalSpecifier(specifier) {
1254
+ const match = specifier.match(/^(.+):([A-Z][a-zA-Z0-9]*)$/);
1255
+ if (match) {
1256
+ const [, basePath, gadgetName] = match;
1257
+ return { path: basePath, gadgetName };
1258
+ }
1259
+ return { path: specifier };
1260
+ }
1230
1261
  function isFileLikeSpecifier(specifier) {
1231
1262
  return PATH_PREFIXES.some((prefix) => specifier.startsWith(prefix)) || specifier.includes(path5.sep);
1232
1263
  }
@@ -1310,7 +1341,10 @@ async function loadGadgets(specifiers, cwd, importer = (specifier) => import(spe
1310
1341
  throw new Error(`Failed to load external package '${specifier}': ${message}`);
1311
1342
  }
1312
1343
  }
1313
- const resolved = resolveGadgetSpecifier(specifier, cwd);
1344
+ const localSpec = isFileLikeSpecifier(specifier) ? parseLocalSpecifier(specifier) : null;
1345
+ const pathToResolve = localSpec?.path ?? specifier;
1346
+ const gadgetNameFilter = localSpec?.gadgetName;
1347
+ const resolved = resolveGadgetSpecifier(pathToResolve, cwd);
1314
1348
  let exports;
1315
1349
  try {
1316
1350
  exports = await importer(resolved);
@@ -1325,6 +1359,17 @@ async function loadGadgets(specifiers, cwd, importer = (specifier) => import(spe
1325
1359
  const message = error instanceof Error ? error.message : String(error);
1326
1360
  throw new Error(`Failed to initialize gadgets from module '${specifier}': ${message}`);
1327
1361
  }
1362
+ if (gadgetNameFilter) {
1363
+ const filtered = extracted.filter(
1364
+ (g) => g.name?.toLowerCase() === gadgetNameFilter.toLowerCase()
1365
+ );
1366
+ if (filtered.length === 0) {
1367
+ throw new Error(
1368
+ `Gadget '${gadgetNameFilter}' not found in module '${pathToResolve}'. Available gadgets: ${extracted.map((g) => g.name).join(", ")}`
1369
+ );
1370
+ }
1371
+ extracted = filtered;
1372
+ }
1328
1373
  if (extracted.length === 0) {
1329
1374
  throw new Error(`Module '${specifier}' does not export any Gadget instances.`);
1330
1375
  }