@looplia/looplia-cli 0.7.5 → 0.8.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.
@@ -33,8 +33,9 @@ import {
33
33
  validateConfig,
34
34
  writeLoopliaSettings,
35
35
  writeUserProfile
36
- } from "./chunk-GIZRTNY3.js";
37
- import "./chunk-VRBGWKZ6.js";
36
+ } from "./chunk-RAFHASLI.js";
37
+ import "./chunk-JJCGDGRS.js";
38
+ import "./chunk-326UJHZM.js";
38
39
  import "./chunk-Y55L47HC.js";
39
40
  export {
40
41
  DEFAULT_SETTINGS,
package/dist/cli.js CHANGED
@@ -8,8 +8,8 @@ import {
8
8
  loadCompiledRegistry,
9
9
  removeSkill,
10
10
  updateSkill
11
- } from "./chunk-4TKNQ5RW.js";
12
- import "./chunk-QQGRKUSM.js";
11
+ } from "./chunk-QKGHHAFR.js";
12
+ import "./chunk-3WLHRD63.js";
13
13
  import {
14
14
  addSource,
15
15
  compileRegistry,
@@ -17,27 +17,23 @@ import {
17
17
  initializeRegistry,
18
18
  loadSources,
19
19
  removeSource
20
- } from "./chunk-XTUQVJYH.js";
20
+ } from "./chunk-MTYPUSCH.js";
21
21
  import "./chunk-APZNHRV3.js";
22
22
  import {
23
23
  DEFAULT_SETTINGS,
24
24
  PRESETS,
25
25
  applyPreset,
26
- copyPlugins,
27
26
  createBuildHooks,
28
27
  createClaudeAgentExecutor,
29
28
  createWorkflowHooks,
30
- downloadRemotePlugins,
31
29
  ensureWorkspace,
32
30
  extractWorkflowSkills,
33
31
  generateValidationManifest,
34
32
  getConfigPath,
35
33
  getFinalStep,
36
- getLoopliaPluginPath,
37
34
  getSettingsDisplayInfo,
38
35
  initializeCommandEnvironment,
39
36
  isInputlessWorkflow,
40
- isLoopliaInitialized,
41
37
  maskAuthToken,
42
38
  parseWorkflow,
43
39
  readLoopliaSettings,
@@ -46,14 +42,20 @@ import {
46
42
  validateUserProfile,
47
43
  writeLoopliaSettings,
48
44
  writeUserProfile
49
- } from "./chunk-GIZRTNY3.js";
50
- import "./chunk-VRBGWKZ6.js";
45
+ } from "./chunk-RAFHASLI.js";
51
46
  import {
52
47
  copyOutputsToDestination,
53
48
  createSandboxDirectories,
54
49
  generateSandboxId,
55
50
  writeWorkflowArtifact
56
51
  } from "./chunk-VUASEQOQ.js";
52
+ import {
53
+ copyPlugins,
54
+ downloadRemotePlugins,
55
+ getLoopliaPluginPath,
56
+ isLoopliaInitialized
57
+ } from "./chunk-JJCGDGRS.js";
58
+ import "./chunk-326UJHZM.js";
57
59
  import {
58
60
  __commonJS,
59
61
  __dirname,
@@ -501,7 +503,7 @@ var require_react_production = __commonJS({
501
503
  exports.useTransition = function() {
502
504
  return ReactSharedInternals.H.useTransition();
503
505
  };
504
- exports.version = "19.2.3";
506
+ exports.version = "19.2.4";
505
507
  }
506
508
  });
507
509
 
@@ -1472,7 +1474,7 @@ var require_react_development = __commonJS({
1472
1474
  exports.useTransition = function() {
1473
1475
  return resolveDispatcher().useTransition();
1474
1476
  };
1475
- exports.version = "19.2.3";
1477
+ exports.version = "19.2.4";
1476
1478
  "undefined" !== typeof __REACT_DEVTOOLS_GLOBAL_HOOK__ && "function" === typeof __REACT_DEVTOOLS_GLOBAL_HOOK__.registerInternalModuleStop && __REACT_DEVTOOLS_GLOBAL_HOOK__.registerInternalModuleStop(Error());
1477
1479
  })();
1478
1480
  }
@@ -25127,6 +25129,7 @@ var base_exports = {};
25127
25129
  __export(base_exports, {
25128
25130
  ConEmu: () => ConEmu,
25129
25131
  beep: () => beep,
25132
+ beginSynchronizedOutput: () => beginSynchronizedOutput,
25130
25133
  clearScreen: () => clearScreen,
25131
25134
  clearTerminal: () => clearTerminal,
25132
25135
  clearViewport: () => clearViewport,
@@ -25144,6 +25147,7 @@ __export(base_exports, {
25144
25147
  cursorShow: () => cursorShow,
25145
25148
  cursorTo: () => cursorTo,
25146
25149
  cursorUp: () => cursorUp,
25150
+ endSynchronizedOutput: () => endSynchronizedOutput,
25147
25151
  enterAlternativeScreen: () => enterAlternativeScreen,
25148
25152
  eraseDown: () => eraseDown,
25149
25153
  eraseEndLine: () => eraseEndLine,
@@ -25158,7 +25162,8 @@ __export(base_exports, {
25158
25162
  link: () => link,
25159
25163
  scrollDown: () => scrollDown,
25160
25164
  scrollUp: () => scrollUp,
25161
- setCwd: () => setCwd
25165
+ setCwd: () => setCwd,
25166
+ synchronizedOutput: () => synchronizedOutput
25162
25167
  });
25163
25168
  init_esm_shims();
25164
25169
  import process2 from "process";
@@ -25276,6 +25281,9 @@ var isOldWindows = () => {
25276
25281
  var clearTerminal = isOldWindows() ? `${eraseScreen}${ESC}0f` : `${eraseScreen}${ESC}3J${ESC}H`;
25277
25282
  var enterAlternativeScreen = ESC + "?1049h";
25278
25283
  var exitAlternativeScreen = ESC + "?1049l";
25284
+ var beginSynchronizedOutput = ESC + "?2026h";
25285
+ var endSynchronizedOutput = ESC + "?2026l";
25286
+ var synchronizedOutput = (text) => beginSynchronizedOutput + text + endSynchronizedOutput;
25279
25287
  var beep = BEL;
25280
25288
  var link = (text, url) => {
25281
25289
  const openLink = wrapOsc(`${OSC}8${SEP}${SEP}${url}${BEL}`);
@@ -27661,7 +27669,7 @@ function sliceAnsi(string, start, end) {
27661
27669
  // ../../node_modules/string-width/index.js
27662
27670
  init_esm_shims();
27663
27671
  var segmenter3 = new Intl.Segmenter();
27664
- var zeroWidthClusterRegex = /^(?:\p{Default_Ignorable_Code_Point}|\p{Control}|\p{Mark}|\p{Surrogate})+$/v;
27672
+ var zeroWidthClusterRegex = /^(?:\p{Default_Ignorable_Code_Point}|\p{Control}|\p{Format}|\p{Mark}|\p{Surrogate})+$/v;
27665
27673
  var leadingNonPrintingRegex = /^[\p{Default_Ignorable_Code_Point}\p{Control}\p{Format}\p{Mark}\p{Surrogate}]+/v;
27666
27674
  var rgiEmojiRegex = /^\p{RGI_Emoji}$/v;
27667
27675
  function baseVisible(segment) {
@@ -29283,8 +29291,8 @@ for (const [start, end] of ansi_styles_default.codes) {
29283
29291
  endCodesSet2.add(ansi_styles_default.color.ansi(end));
29284
29292
  endCodesMap2.set(ansi_styles_default.color.ansi(start), ansi_styles_default.color.ansi(end));
29285
29293
  }
29286
- var linkStartCodePrefix = "\x1B]8;;";
29287
- var linkStartCodePrefixCharCodes = linkStartCodePrefix.split("").map((char) => char.charCodeAt(0));
29294
+ var linkCodePrefix = "\x1B]8;";
29295
+ var linkCodePrefixCharCodes = linkCodePrefix.split("").map((char) => char.charCodeAt(0));
29288
29296
  var linkCodeSuffix = "\x07";
29289
29297
  var linkCodeSuffixCharCode = linkCodeSuffix.charCodeAt(0);
29290
29298
  var linkEndCode = `\x1B]8;;${linkCodeSuffix}`;
@@ -29293,7 +29301,7 @@ function getEndCode2(code) {
29293
29301
  return code;
29294
29302
  if (endCodesMap2.has(code))
29295
29303
  return endCodesMap2.get(code);
29296
- if (code.startsWith(linkStartCodePrefix))
29304
+ if (code.startsWith(linkCodePrefix))
29297
29305
  return linkEndCode;
29298
29306
  code = code.slice(2);
29299
29307
  if (code.startsWith("38")) {
@@ -29413,12 +29421,15 @@ function styledCharsToString(chars) {
29413
29421
  init_esm_shims();
29414
29422
  function parseLinkCode(string, offset) {
29415
29423
  string = string.slice(offset);
29416
- for (let index = 1; index < linkStartCodePrefixCharCodes.length; index++) {
29417
- if (string.charCodeAt(index) !== linkStartCodePrefixCharCodes[index]) {
29424
+ for (let index = 1; index < linkCodePrefixCharCodes.length; index++) {
29425
+ if (string.charCodeAt(index) !== linkCodePrefixCharCodes[index]) {
29418
29426
  return void 0;
29419
29427
  }
29420
29428
  }
29421
- const endIndex = string.indexOf("\x07", linkStartCodePrefix.length);
29429
+ const paramsEndIndex = string.indexOf(";", linkCodePrefix.length);
29430
+ if (paramsEndIndex === -1)
29431
+ return void 0;
29432
+ const endIndex = string.indexOf("\x07", paramsEndIndex + 1);
29422
29433
  if (endIndex === -1)
29423
29434
  return void 0;
29424
29435
  return string.slice(0, endIndex + 1);
@@ -32872,7 +32883,7 @@ async function* analyzeDescriptionStreaming(description, workspace, questionCall
32872
32883
  const { createSandboxDirectories: createSandboxDirectories2, generateSandboxId: generateSandboxId2 } = await import("./sandbox-XVMNWAJO.js");
32873
32884
  const sandboxId = generateSandboxId2("build");
32874
32885
  createSandboxDirectories2(workspace, sandboxId);
32875
- const { executeInteractiveQueryStreaming } = await import("./claude-agent-sdk-W5MXMV4Q.js");
32886
+ const { executeInteractiveQueryStreaming } = await import("./claude-agent-sdk-FNYGQYFW.js");
32876
32887
  const prompt = `${buildAnalysisPrompt(description)} --sandbox-id ${sandboxId}`;
32877
32888
  const generator = executeInteractiveQueryStreaming(
32878
32889
  prompt,
@@ -34019,6 +34030,8 @@ function processArg(result, arg, nextArg, descriptionParts) {
34019
34030
  result.noInteractive = true;
34020
34031
  } else if (arg === "--mock") {
34021
34032
  result.mock = true;
34033
+ } else if (arg === "--skip-research" || arg === "--offline") {
34034
+ result.skipResearch = true;
34022
34035
  } else if (!arg.startsWith("-")) {
34023
34036
  descriptionParts.push(arg);
34024
34037
  }
@@ -34029,7 +34042,8 @@ function parseArgs(args) {
34029
34042
  description: "",
34030
34043
  noInteractive: false,
34031
34044
  mock: false,
34032
- help: false
34045
+ help: false,
34046
+ skipResearch: false
34033
34047
  };
34034
34048
  let skipNext = false;
34035
34049
  for (const [index, arg] of args.entries()) {
@@ -34059,18 +34073,26 @@ Options:
34059
34073
  --output, -o <path> Output directory (default: ~/.looplia/workflows/)
34060
34074
  --name, -n <name> Workflow filename (derived from description if not set)
34061
34075
  --no-interactive Skip TUI, batch mode
34076
+ --skip-research Skip skill auto-discovery (use local skills only)
34077
+ --offline Alias for --skip-research
34062
34078
  --mock Use mock mode (no API calls)
34063
34079
  --help, -h Show this help
34064
34080
 
34081
+ Skill Auto-Discovery (v0.8.0):
34082
+ By default, build searches skills.sh for relevant skills based on your
34083
+ description and installs them to ~/.looplia/plugins/auto-discovery-plugin/.
34084
+ Use --skip-research to disable this and use only locally installed skills.
34085
+
34065
34086
  Examples:
34066
34087
  looplia build
34067
34088
  looplia build "analyze videos and create blog outlines"
34068
34089
  looplia build "summarize articles" --name article-summary
34069
34090
  looplia build "..." --no-interactive --name my-workflow
34091
+ looplia build "..." --skip-research # Skip skill discovery
34070
34092
  `);
34071
34093
  }
34072
34094
  function getWorkspacePath() {
34073
- return resolve(homedir2(), ".looplia");
34095
+ return process.env.LOOPLIA_HOME ?? resolve(homedir2(), ".looplia");
34074
34096
  }
34075
34097
  function ensureWorkspace2(mock) {
34076
34098
  const workspace = getWorkspacePath();
@@ -34191,7 +34213,7 @@ async function* executeInteractiveStreamingBatch(prompt, workspace, questionCall
34191
34213
  process.env.LOOPLIA_SANDBOX_ID = sandboxId;
34192
34214
  process.env.LOOPLIA_SANDBOX_ROOT = join2(workspace, "sandbox");
34193
34215
  const promptWithSandbox = `${prompt} --sandbox-id ${sandboxId}`;
34194
- const { executeInteractiveQueryStreaming } = await import("./claude-agent-sdk-W5MXMV4Q.js");
34216
+ const { executeInteractiveQueryStreaming } = await import("./claude-agent-sdk-FNYGQYFW.js");
34195
34217
  const schema = {
34196
34218
  type: "object",
34197
34219
  properties: {
@@ -34397,6 +34419,66 @@ function renderResult(result, workspace) {
34397
34419
  const displayPath = writtenPath ?? result.workflowPath ?? null;
34398
34420
  renderSuccessMessage(result, displayPath);
34399
34421
  }
34422
+ async function researchAndInstallSkills(description, interactive) {
34423
+ const {
34424
+ searchSkills,
34425
+ fetchSkillContent,
34426
+ installSkillToAutoDiscovery,
34427
+ isSkillAutoDiscovered
34428
+ } = await import("./discovery-22DBV6CT.js");
34429
+ console.log("Researching skills for workflow...");
34430
+ const results = await searchSkills(description);
34431
+ if (results.length === 0) {
34432
+ console.log("No additional skills found, using local catalog");
34433
+ return [];
34434
+ }
34435
+ let selectedSkills;
34436
+ if (interactive) {
34437
+ console.log(`Found ${results.length} potential skills:`);
34438
+ for (const [i, skill] of results.slice(0, 5).entries()) {
34439
+ console.log(` ${i + 1}. ${skill.name} - ${skill.description}`);
34440
+ }
34441
+ selectedSkills = results.slice(0, 3);
34442
+ console.log(`Auto-selecting top ${selectedSkills.length} skills...`);
34443
+ } else {
34444
+ selectedSkills = results.slice(0, 3);
34445
+ }
34446
+ const installedNames = [];
34447
+ for (const skill of selectedSkills) {
34448
+ if (await isSkillAutoDiscovered(skill.name)) {
34449
+ console.log(` Skipped: ${skill.name} (already installed)`);
34450
+ installedNames.push(skill.name);
34451
+ continue;
34452
+ }
34453
+ try {
34454
+ const content = await fetchSkillContent(
34455
+ skill.owner,
34456
+ skill.repo,
34457
+ skill.name
34458
+ );
34459
+ const sourceUrl = `https://github.com/${skill.owner}/${skill.repo}`;
34460
+ await installSkillToAutoDiscovery(skill.name, content, sourceUrl);
34461
+ installedNames.push(skill.name);
34462
+ console.log(` Installed: ${skill.name}`);
34463
+ } catch (error) {
34464
+ const msg = error instanceof Error ? error.message : String(error);
34465
+ console.warn(` Failed to install ${skill.name}: ${msg}`);
34466
+ }
34467
+ }
34468
+ if (installedNames.length > 0) {
34469
+ console.log(`Installed ${installedNames.length} skills for workflow`);
34470
+ }
34471
+ return installedNames;
34472
+ }
34473
+ async function trySkillResearch(description, interactive) {
34474
+ try {
34475
+ await researchAndInstallSkills(description, interactive);
34476
+ } catch (error) {
34477
+ console.warn(
34478
+ `Skill research failed: ${error instanceof Error ? error.message : error}`
34479
+ );
34480
+ }
34481
+ }
34400
34482
  async function runBuildCommand(args) {
34401
34483
  const parsed = parseArgs(args);
34402
34484
  if (parsed.help) {
@@ -34405,6 +34487,12 @@ async function runBuildCommand(args) {
34405
34487
  }
34406
34488
  try {
34407
34489
  const workspace = ensureWorkspace2(parsed.mock);
34490
+ if (!(parsed.mock || parsed.skipResearch) && parsed.description) {
34491
+ await trySkillResearch(
34492
+ parsed.description,
34493
+ isInteractive() && !parsed.noInteractive
34494
+ );
34495
+ }
34408
34496
  if (!parsed.mock) {
34409
34497
  try {
34410
34498
  await compileRegistry({ localOnly: true });
@@ -34883,19 +34971,19 @@ Description:
34883
34971
  Installs the looplia plugin to ~/.looplia for use with Claude Code.
34884
34972
 
34885
34973
  Default mode (npm bundle):
34886
- - Copies bundled plugins from npm package to ~/.looplia
34974
+ - Copies bundled plugins from npm package to ~/.looplia/plugins/
34887
34975
  - Installs looplia-core (workflow engine) + looplia-writer (writing domain)
34888
34976
 
34889
34977
  Remote mode (--remote):
34890
34978
  - Downloads plugins from GitHub release
34891
34979
  - Use --remote v0.6.5 for specific version
34892
34980
 
34893
- Created structure:
34981
+ Created structure (v0.8.0):
34894
34982
  ~/.looplia/
34895
- \u251C\u2500\u2500 looplia-core/ Core workflow engine
34896
- \u2502 \u2514\u2500\u2500 .claude-plugin/ Plugin manifest
34897
- \u251C\u2500\u2500 looplia-writer/ Writing domain plugin
34898
- \u2502 \u2514\u2500\u2500 .claude-plugin/ Plugin manifest
34983
+ \u251C\u2500\u2500 plugins/ All plugins (unified location)
34984
+ \u2502 \u251C\u2500\u2500 looplia-core/ Core workflow engine
34985
+ \u2502 \u251C\u2500\u2500 looplia-writer/ Writing domain plugin
34986
+ \u2502 \u2514\u2500\u2500 auto-discovery-plugin/ Auto-discovered skills (created by build)
34899
34987
  \u251C\u2500\u2500 workflows/ Workflow templates
34900
34988
  \u251C\u2500\u2500 sandbox/ Execution isolation
34901
34989
  \u2514\u2500\u2500 user-profile.json User preferences
@@ -34950,7 +35038,7 @@ function printInitSuccess(targetDir) {
34950
35038
  console.log("");
34951
35039
  console.log(`Looplia initialized at ${targetDir}`);
34952
35040
  console.log("");
34953
- console.log("Installed plugins:");
35041
+ console.log("Installed plugins (in plugins/):");
34954
35042
  console.log(" - looplia-core/ (workflow engine)");
34955
35043
  console.log(" - looplia-writer/ (writing domain)");
34956
35044
  console.log("");
@@ -35403,7 +35491,7 @@ Examples:
35403
35491
  `);
35404
35492
  }
35405
35493
  function getWorkspacePath2() {
35406
- return resolve2(homedir3(), ".looplia");
35494
+ return process.env.LOOPLIA_HOME ?? resolve2(homedir3(), ".looplia");
35407
35495
  }
35408
35496
  function ensureWorkspace3(mock) {
35409
35497
  const workspace = getWorkspacePath2();
@@ -35684,6 +35772,7 @@ Usage:
35684
35772
 
35685
35773
  Subcommands:
35686
35774
  add <name|url> Install skill by name or GitHub URL
35775
+ search <query> Search skills.sh registry
35687
35776
  list List installed/available skills
35688
35777
  info <name> Show skill details
35689
35778
  remove <name> Remove skill from workspace
@@ -35700,6 +35789,7 @@ Examples:
35700
35789
  looplia skill add custom-analyzer --from github:user/repo
35701
35790
  looplia skill add https://github.com/user/my-skill
35702
35791
  looplia skill add https://github.com/anthropics/skills/tree/main/skills/algorithmic-art
35792
+ looplia skill search "pdf processing"
35703
35793
  looplia skill list
35704
35794
  looplia skill list --available
35705
35795
  looplia skill info media-reviewer
@@ -35744,7 +35834,7 @@ async function skillAdd(nameOrUrl, from) {
35744
35834
  }
35745
35835
  if (GITHUB_URL_PATTERN.test(nameOrUrl)) {
35746
35836
  console.log(`Installing skill from URL: ${nameOrUrl}...`);
35747
- const { installSkillFromUrl } = await import("./dist-3XSIQAV3.js");
35837
+ const { installSkillFromUrl } = await import("./dist-HMIWVZMJ.js");
35748
35838
  const result2 = await installSkillFromUrl(nameOrUrl, true);
35749
35839
  switch (result2.status) {
35750
35840
  case "installed":
@@ -35944,6 +36034,106 @@ async function skillUpdate(name) {
35944
36034
  console.log(`Unexpected status: ${result.status}`);
35945
36035
  }
35946
36036
  }
36037
+ function displaySearchResults(results) {
36038
+ console.log(`
36039
+ Found ${results.length} skill(s):
36040
+ `);
36041
+ console.log("\u2500".repeat(80));
36042
+ console.log(
36043
+ " # NAME OWNER/REPO DESCRIPTION"
36044
+ );
36045
+ console.log("\u2500".repeat(80));
36046
+ for (const [index, result] of results.entries()) {
36047
+ const num = String(index + 1).padStart(2);
36048
+ const name = result.name.padEnd(20);
36049
+ const repo = `${result.owner}/${result.repo}`.padEnd(28);
36050
+ const desc = result.description.length > 25 ? `${result.description.slice(0, 22)}...` : result.description;
36051
+ console.log(` ${num} ${name} ${repo} ${desc}`);
36052
+ }
36053
+ console.log("\u2500".repeat(80));
36054
+ }
36055
+ async function promptSkillSelection() {
36056
+ const readline = await import("readline");
36057
+ const rl = readline.createInterface({
36058
+ input: process.stdin,
36059
+ output: process.stdout
36060
+ });
36061
+ const answer = await new Promise((resolve3) => {
36062
+ rl.question(
36063
+ "\nEnter number(s) to install (comma-separated), or 'q' to quit: ",
36064
+ resolve3
36065
+ );
36066
+ });
36067
+ rl.close();
36068
+ return answer;
36069
+ }
36070
+ function parseSkillSelection(answer, results) {
36071
+ const indices = answer.split(",").map((s) => Number.parseInt(s.trim(), 10) - 1);
36072
+ return indices.filter((i) => i >= 0 && i < results.length).map((i) => results[i]).filter((s) => s !== void 0);
36073
+ }
36074
+ async function installSelectedSkills(selected) {
36075
+ const { fetchSkillContent, installSkillToAutoDiscovery } = await import("./discovery-22DBV6CT.js");
36076
+ console.log(`
36077
+ Installing ${selected.length} skill(s)...`);
36078
+ let installedCount = 0;
36079
+ for (const skill of selected) {
36080
+ try {
36081
+ const content = await fetchSkillContent(
36082
+ skill.owner,
36083
+ skill.repo,
36084
+ skill.name
36085
+ );
36086
+ const sourceUrl = `https://github.com/${skill.owner}/${skill.repo}`;
36087
+ const installResult = await installSkillToAutoDiscovery(
36088
+ skill.name,
36089
+ content,
36090
+ sourceUrl
36091
+ );
36092
+ console.log(` \u2713 Installed: ${skill.name} \u2192 ${installResult.path}`);
36093
+ installedCount += 1;
36094
+ } catch (error) {
36095
+ const msg = error instanceof Error ? error.message : String(error);
36096
+ console.error(` \u2717 Failed to install ${skill.name}: ${msg}`);
36097
+ }
36098
+ }
36099
+ return installedCount;
36100
+ }
36101
+ async function skillSearch(query) {
36102
+ if (!query) {
36103
+ console.error("Error: Search query required");
36104
+ console.error("Usage: looplia skill search <query>");
36105
+ process.exit(1);
36106
+ }
36107
+ console.log(`Searching skills.sh for: ${query}...`);
36108
+ const { searchSkills } = await import("./discovery-22DBV6CT.js");
36109
+ const results = await searchSkills(query);
36110
+ if (results.length === 0) {
36111
+ console.log("No skills found matching your query.");
36112
+ return;
36113
+ }
36114
+ displaySearchResults(results);
36115
+ if (!process.stdin.isTTY) {
36116
+ console.log("\nTo install a skill, run: looplia skill add <name>");
36117
+ return;
36118
+ }
36119
+ const answer = await promptSkillSelection();
36120
+ if (answer.toLowerCase() === "q" || !answer.trim()) {
36121
+ console.log("No skills installed.");
36122
+ return;
36123
+ }
36124
+ const selected = parseSkillSelection(answer, results);
36125
+ if (selected.length === 0) {
36126
+ console.log("No valid selection. No skills installed.");
36127
+ return;
36128
+ }
36129
+ const installedCount = await installSelectedSkills(selected);
36130
+ if (installedCount > 0) {
36131
+ console.log("\nUpdating skill catalog...");
36132
+ const { compileRegistry: compileRegistry2 } = await import("./dist-HMIWVZMJ.js");
36133
+ await compileRegistry2({ localOnly: true });
36134
+ console.log("\u2713 Skill catalog updated");
36135
+ }
36136
+ }
35947
36137
  async function runSkillCommand(args) {
35948
36138
  const subcommand = args[0];
35949
36139
  if (!subcommand || subcommand === "--help" || subcommand === "-h") {
@@ -35961,6 +36151,9 @@ async function runSkillCommand(args) {
35961
36151
  case "add":
35962
36152
  await skillAdd(positionalArgs[1] ?? "", from);
35963
36153
  break;
36154
+ case "search":
36155
+ await skillSearch(positionalArgs[1] ?? "");
36156
+ break;
35964
36157
  case "list":
35965
36158
  await skillList({ installed: hasInstalled, available: hasAvailable });
35966
36159
  break;
@@ -35981,7 +36174,7 @@ async function runSkillCommand(args) {
35981
36174
  }
35982
36175
 
35983
36176
  // src/index.ts
35984
- var VERSION = "0.7.5";
36177
+ var VERSION = "0.8.0";
35985
36178
  function printHelp5() {
35986
36179
  console.log(`
35987
36180
  looplia - Content intelligence CLI (v${VERSION})
@@ -12,13 +12,13 @@ import {
12
12
  loadSources,
13
13
  removeSource,
14
14
  saveSources
15
- } from "./chunk-XTUQVJYH.js";
16
- import "./chunk-VRBGWKZ6.js";
15
+ } from "./chunk-MTYPUSCH.js";
16
+ import "./chunk-326UJHZM.js";
17
17
  import {
18
18
  init_esm_shims
19
19
  } from "./chunk-Y55L47HC.js";
20
20
 
21
- // ../../packages/provider/dist/compiler-4B63UTUP.js
21
+ // ../../packages/provider/dist/compiler-QKB2ZYNK.js
22
22
  init_esm_shims();
23
23
  export {
24
24
  DEFAULT_MARKETPLACE_SOURCES,