@looplia/looplia-cli 0.7.2 → 0.7.3

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.
@@ -7,7 +7,7 @@ import {
7
7
  init_esm_shims
8
8
  } from "./chunk-Y55L47HC.js";
9
9
 
10
- // ../../packages/provider/dist/chunk-Q57VKNQX.js
10
+ // ../../packages/provider/dist/chunk-DRG2TRPF.js
11
11
  init_esm_shims();
12
12
  import { createHash } from "crypto";
13
13
  import {
@@ -175,7 +175,7 @@ async function copyPlugins(targetDir, sourcePath) {
175
175
  );
176
176
  const { initializeRegistry, compileRegistry } = await import("./compiler-4B63UTUP-VE77VSJ2.js");
177
177
  await initializeRegistry();
178
- const { syncRegistrySources } = await import("./sync-MFM46YAB-SSBMNJ7D.js");
178
+ const { syncRegistrySources } = await import("./sync-E5PGFGNI-IGGJR7IL.js");
179
179
  const syncResults = await syncRegistrySources({ showProgress: true });
180
180
  for (const result of syncResults) {
181
181
  if (result.status === "failed") {
@@ -293,7 +293,7 @@ async function getPluginPaths() {
293
293
  return await getProdPluginPaths();
294
294
  }
295
295
 
296
- // ../../packages/provider/dist/chunk-OG5PVVUV.js
296
+ // ../../packages/provider/dist/chunk-3N4TZG2S.js
297
297
  init_esm_shims();
298
298
  import { execSync } from "child_process";
299
299
  import { existsSync as existsSync3 } from "fs";
@@ -22127,7 +22127,7 @@ function query({
22127
22127
  return queryInstance;
22128
22128
  }
22129
22129
 
22130
- // ../../packages/provider/dist/chunk-OG5PVVUV.js
22130
+ // ../../packages/provider/dist/chunk-3N4TZG2S.js
22131
22131
  import { appendFileSync as appendFileSync3, mkdirSync as mkdirSync3, writeFileSync } from "fs";
22132
22132
  import { join as join33 } from "path";
22133
22133
  import { cp as cp2, mkdir as mkdir22, readFile as readFile22, rm as rm22, writeFile as writeFile22 } from "fs/promises";
@@ -15,7 +15,7 @@ import {
15
15
  init_esm_shims
16
16
  } from "./chunk-Y55L47HC.js";
17
17
 
18
- // ../../packages/provider/dist/chunk-3D6TVN6A.js
18
+ // ../../packages/provider/dist/chunk-O57P5VMU.js
19
19
  init_esm_shims();
20
20
  import { exec } from "child_process";
21
21
  import { cp, mkdir, readdir, readFile, rm, writeFile } from "fs/promises";
@@ -111,6 +111,8 @@ async function copyPluginSkills(plugin, tempDir, pluginDir) {
111
111
  const destPath = join(pluginDir, "skills", skillName);
112
112
  if (await pathExists(srcPath)) {
113
113
  await cp(srcPath, destPath, { recursive: true });
114
+ } else {
115
+ console.warn(`Warning: Skill path not found in source: ${skillPath}`);
114
116
  }
115
117
  }
116
118
  } else {
@@ -118,6 +120,8 @@ async function copyPluginSkills(plugin, tempDir, pluginDir) {
118
120
  const destPath = join(pluginDir, "skills", plugin.name);
119
121
  if (await pathExists(srcPath)) {
120
122
  await cp(srcPath, destPath, { recursive: true });
123
+ } else {
124
+ console.warn(`Warning: Skill source not found: ${plugin.source}`);
121
125
  }
122
126
  }
123
127
  }
@@ -157,7 +161,11 @@ async function installMarketplaceSource(tempDir, source, pluginsDir) {
157
161
  const results = [];
158
162
  for (const plugin of manifest.plugins) {
159
163
  const pluginDir = join(pluginsDir, plugin.name);
164
+ const skillsDir = join(pluginDir, "skills");
160
165
  try {
166
+ if (await pathExists(skillsDir)) {
167
+ await rm(skillsDir, { recursive: true, force: true });
168
+ }
161
169
  await createPluginStructure({ pluginDir, plugin, marketplace });
162
170
  await copyPluginSkills(plugin, tempDir, pluginDir);
163
171
  results.push({
@@ -6,7 +6,13 @@ import {
6
6
  // src/utils/sandbox.ts
7
7
  init_esm_shims();
8
8
  import { randomBytes } from "crypto";
9
- import { copyFileSync, mkdirSync, readdirSync } from "fs";
9
+ import {
10
+ copyFileSync,
11
+ existsSync,
12
+ mkdirSync,
13
+ readdirSync,
14
+ writeFileSync
15
+ } from "fs";
10
16
  import { join, resolve } from "path";
11
17
  var SANDBOX_DIRS = {
12
18
  INPUTS: "inputs",
@@ -63,6 +69,24 @@ function copyOutputsToDestination(workspace, sandboxId, destDir) {
63
69
  }
64
70
  return copiedCount;
65
71
  }
72
+ function writeWorkflowArtifact(workspace, filename, content) {
73
+ if (!(workspace && filename && content)) {
74
+ return null;
75
+ }
76
+ try {
77
+ const workflowsDir = join(workspace, "workflows");
78
+ mkdirSync(workflowsDir, { recursive: true });
79
+ const filePath = join(workflowsDir, filename);
80
+ writeFileSync(filePath, content, "utf-8");
81
+ if (!existsSync(filePath)) {
82
+ return null;
83
+ }
84
+ return filePath;
85
+ } catch (error) {
86
+ console.warn(`Warning: Error writing workflow artifact: ${error}`);
87
+ return null;
88
+ }
89
+ }
66
90
 
67
91
  export {
68
92
  SANDBOX_DIRS,
@@ -70,5 +94,6 @@ export {
70
94
  generateSlug,
71
95
  generateSandboxId,
72
96
  createSandboxDirectories,
73
- copyOutputsToDestination
97
+ copyOutputsToDestination,
98
+ writeWorkflowArtifact
74
99
  };
@@ -107,7 +107,7 @@ import {
107
107
  unknownType,
108
108
  util,
109
109
  voidType
110
- } from "./chunk-OIE7CSW6.js";
110
+ } from "./chunk-MHR5TPHE.js";
111
111
  import {
112
112
  pathExists
113
113
  } from "./chunk-VRBGWKZ6.js";
@@ -360,7 +360,7 @@ var RUN_PATTERN = /^agents\/([a-z][a-z0-9-]*)$/;
360
360
  function isValidRunFormat(run) {
361
361
  return RUN_PATTERN.test(run);
362
362
  }
363
- var INPUTLESS_CAPABLE_SKILLS = ["search"];
363
+ var INPUTLESS_CAPABLE_SKILLS = ["browser-research"];
364
364
  var ARRAY_PATTERN = /^\[(.*)\]$/;
365
365
  var INTEGER_PATTERN = /^\d+$/;
366
366
  var NON_SPACE_PATTERN = /\S/;
@@ -904,7 +904,7 @@ async function installThirdPartySkill(skill, showProgress = false) {
904
904
  priority: 0,
905
905
  addedAt: (/* @__PURE__ */ new Date()).toISOString()
906
906
  };
907
- const { syncSource: sync } = await import("./sync-MFM46YAB-SSBMNJ7D.js");
907
+ const { syncSource: sync } = await import("./sync-E5PGFGNI-IGGJR7IL.js");
908
908
  const result = await sync(source, {
909
909
  showProgress,
910
910
  skillPath: skill.skillPath
@@ -1036,7 +1036,7 @@ async function installSkillFromUrl(url, showProgress = false) {
1036
1036
  priority: 0,
1037
1037
  addedAt: (/* @__PURE__ */ new Date()).toISOString()
1038
1038
  };
1039
- const { syncSource: sync } = await import("./sync-MFM46YAB-SSBMNJ7D.js");
1039
+ const { syncSource: sync } = await import("./sync-E5PGFGNI-IGGJR7IL.js");
1040
1040
  const result = await sync(source, {
1041
1041
  showProgress,
1042
1042
  skillPath
@@ -31,7 +31,7 @@ import {
31
31
  validateConfig,
32
32
  writeLoopliaSettings,
33
33
  writeUserProfile
34
- } from "./chunk-OIE7CSW6.js";
34
+ } from "./chunk-MHR5TPHE.js";
35
35
  import "./chunk-VRBGWKZ6.js";
36
36
  import "./chunk-Y55L47HC.js";
37
37
  export {
package/dist/cli.js CHANGED
@@ -12,8 +12,8 @@ import {
12
12
  removeSkill,
13
13
  updateSkill,
14
14
  validateUserProfile
15
- } from "./chunk-2ETB5RP7.js";
16
- import "./chunk-HMJDIX7C.js";
15
+ } from "./chunk-VYGRYFSY.js";
16
+ import "./chunk-QQGRKUSM.js";
17
17
  import {
18
18
  addSource,
19
19
  compileRegistry,
@@ -42,13 +42,14 @@ import {
42
42
  removeLoopliaSettings,
43
43
  writeLoopliaSettings,
44
44
  writeUserProfile
45
- } from "./chunk-OIE7CSW6.js";
45
+ } from "./chunk-MHR5TPHE.js";
46
46
  import "./chunk-VRBGWKZ6.js";
47
47
  import {
48
48
  copyOutputsToDestination,
49
49
  createSandboxDirectories,
50
- generateSandboxId
51
- } from "./chunk-QLL3W74D.js";
50
+ generateSandboxId,
51
+ writeWorkflowArtifact
52
+ } from "./chunk-VUASEQOQ.js";
52
53
  import {
53
54
  __commonJS,
54
55
  __dirname,
@@ -32864,10 +32865,10 @@ var ANALYSIS_RESULT_SCHEMA = {
32864
32865
  }
32865
32866
  };
32866
32867
  async function* analyzeDescriptionStreaming(description, workspace, questionCallback) {
32867
- const { createSandboxDirectories: createSandboxDirectories2, generateSandboxId: generateSandboxId2 } = await import("./sandbox-LD3EU4YO.js");
32868
+ const { createSandboxDirectories: createSandboxDirectories2, generateSandboxId: generateSandboxId2 } = await import("./sandbox-XVMNWAJO.js");
32868
32869
  const sandboxId = generateSandboxId2("build");
32869
32870
  createSandboxDirectories2(workspace, sandboxId);
32870
- const { executeInteractiveQueryStreaming } = await import("./claude-agent-sdk-YGNDVP55.js");
32871
+ const { executeInteractiveQueryStreaming } = await import("./claude-agent-sdk-SQ6YU4VE.js");
32871
32872
  const prompt = `${buildAnalysisPrompt(description)} --sandbox-id ${sandboxId}`;
32872
32873
  const generator = executeInteractiveQueryStreaming(
32873
32874
  prompt,
@@ -34112,7 +34113,7 @@ function executeMock(args) {
34112
34113
  }
34113
34114
  async function executeBatch(prompt, workspace, executor) {
34114
34115
  console.error("\u23F3 Building workflow...");
34115
- const { createSandboxDirectories: createSandboxDirectories2, generateSandboxId: generateSandboxId2 } = await import("./sandbox-LD3EU4YO.js");
34116
+ const { createSandboxDirectories: createSandboxDirectories2, generateSandboxId: generateSandboxId2 } = await import("./sandbox-XVMNWAJO.js");
34116
34117
  const sandboxId = generateSandboxId2("build");
34117
34118
  createSandboxDirectories2(workspace, sandboxId);
34118
34119
  const promptWithSandbox = `${prompt} --sandbox-id ${sandboxId}`;
@@ -34130,11 +34131,11 @@ async function executeBatch(prompt, workspace, executor) {
34130
34131
  };
34131
34132
  }
34132
34133
  async function* executeInteractiveStreamingBatch(prompt, workspace, questionCallback) {
34133
- const { createSandboxDirectories: createSandboxDirectories2, generateSandboxId: generateSandboxId2 } = await import("./sandbox-LD3EU4YO.js");
34134
+ const { createSandboxDirectories: createSandboxDirectories2, generateSandboxId: generateSandboxId2 } = await import("./sandbox-XVMNWAJO.js");
34134
34135
  const sandboxId = generateSandboxId2("build");
34135
34136
  createSandboxDirectories2(workspace, sandboxId);
34136
34137
  const promptWithSandbox = `${prompt} --sandbox-id ${sandboxId}`;
34137
- const { executeInteractiveQueryStreaming } = await import("./claude-agent-sdk-YGNDVP55.js");
34138
+ const { executeInteractiveQueryStreaming } = await import("./claude-agent-sdk-SQ6YU4VE.js");
34138
34139
  const schema = {
34139
34140
  type: "object",
34140
34141
  properties: {
@@ -34280,24 +34281,52 @@ function executeBuild(prompt, workspace, parsed) {
34280
34281
  }
34281
34282
  return executeBatch(prompt, workspace);
34282
34283
  }
34283
- function renderResult(result) {
34284
- if (result.status === "success") {
34285
- console.log("\n\u2705 Workflow created successfully");
34286
- if (result.workflowPath) {
34287
- console.log(`Path: ${result.workflowPath}`);
34288
- }
34289
- if (result.workflowName) {
34290
- console.log("\nRun with:");
34291
- console.log(` looplia run ${result.workflowName} --file <content.md>`);
34292
- }
34293
- if (result.stepsCount) {
34294
- console.log(`
34284
+ function handleArtifactWrite(result, workspace) {
34285
+ if (!result.artifact) {
34286
+ console.warn("\u26A0 No artifact in result - workflow may not be saved");
34287
+ return null;
34288
+ }
34289
+ const { filename, content } = result.artifact;
34290
+ if (!(filename && content)) {
34291
+ console.warn("\u26A0 Invalid artifact (missing filename or content)");
34292
+ return null;
34293
+ }
34294
+ const writtenPath = writeWorkflowArtifact(workspace, filename, content);
34295
+ if (!writtenPath) {
34296
+ console.error("\u2718 Failed to write workflow artifact");
34297
+ return null;
34298
+ }
34299
+ return writtenPath;
34300
+ }
34301
+ function renderSuccessMessage(result, displayPath) {
34302
+ console.log("\n\u2705 Workflow created successfully");
34303
+ if (displayPath) {
34304
+ console.log(`Path: ${displayPath}`);
34305
+ }
34306
+ if (result.workflowName || result.workflowId) {
34307
+ const name = result.workflowName ?? result.workflowId;
34308
+ console.log("\nRun with:");
34309
+ console.log(` looplia run ${name} --file <content.md>`);
34310
+ }
34311
+ if (result.stepsCount) {
34312
+ console.log(`
34295
34313
  Steps: ${result.stepsCount}`);
34296
- }
34297
- } else {
34314
+ }
34315
+ }
34316
+ function renderResult(result, workspace) {
34317
+ if (result.status !== "success") {
34298
34318
  console.error(`
34299
34319
  \u274C Build failed: ${result.error ?? "Unknown error"}`);
34320
+ return;
34321
+ }
34322
+ const writtenPath = handleArtifactWrite(result, workspace);
34323
+ const hasValidArtifact = result.artifact?.filename && result.artifact?.content;
34324
+ if (hasValidArtifact && !writtenPath) {
34325
+ console.error("\n\u274C Build failed: Unable to save workflow artifact");
34326
+ return;
34300
34327
  }
34328
+ const displayPath = writtenPath ?? result.workflowPath ?? null;
34329
+ renderSuccessMessage(result, displayPath);
34301
34330
  }
34302
34331
  async function runBuildCommand(args) {
34303
34332
  const parsed = parseArgs(args);
@@ -34316,7 +34345,7 @@ async function runBuildCommand(args) {
34316
34345
  await initializeCommandEnvironment({ mock: parsed.mock });
34317
34346
  const prompt = buildPrompt(parsed);
34318
34347
  const result = await executeBuild(prompt, workspace, parsed);
34319
- renderResult(result);
34348
+ renderResult(result, workspace);
34320
34349
  if (result.status !== "success") {
34321
34350
  process.exit(1);
34322
34351
  }
@@ -35593,7 +35622,7 @@ async function skillAdd(nameOrUrl, from) {
35593
35622
  }
35594
35623
  if (GITHUB_URL_PATTERN.test(nameOrUrl)) {
35595
35624
  console.log(`Installing skill from URL: ${nameOrUrl}...`);
35596
- const { installSkillFromUrl } = await import("./dist-3B4KUA76.js");
35625
+ const { installSkillFromUrl } = await import("./dist-PMEIK6PJ.js");
35597
35626
  const result2 = await installSkillFromUrl(nameOrUrl, true);
35598
35627
  switch (result2.status) {
35599
35628
  case "installed":
@@ -35830,7 +35859,7 @@ async function runSkillCommand(args) {
35830
35859
  }
35831
35860
 
35832
35861
  // src/index.ts
35833
- var VERSION = "0.7.2";
35862
+ var VERSION = "0.7.3";
35834
35863
  function printHelp5() {
35835
35864
  console.log(`
35836
35865
  looplia - Content intelligence CLI (v${VERSION})
@@ -11,11 +11,11 @@ import {
11
11
  loadCompiledRegistry,
12
12
  removeSkill,
13
13
  updateSkill
14
- } from "./chunk-2ETB5RP7.js";
14
+ } from "./chunk-VYGRYFSY.js";
15
15
  import {
16
16
  syncRegistrySources,
17
17
  syncSource
18
- } from "./chunk-HMJDIX7C.js";
18
+ } from "./chunk-QQGRKUSM.js";
19
19
  import {
20
20
  addSource,
21
21
  compileRegistry,
@@ -32,7 +32,7 @@ import {
32
32
  CORE_SKILLS,
33
33
  ensureWorkspace,
34
34
  isCoreSkill
35
- } from "./chunk-OIE7CSW6.js";
35
+ } from "./chunk-MHR5TPHE.js";
36
36
  import "./chunk-VRBGWKZ6.js";
37
37
  import "./chunk-Y55L47HC.js";
38
38
  export {
@@ -5,8 +5,9 @@ import {
5
5
  createSandboxDirectories,
6
6
  generateRandomSuffix,
7
7
  generateSandboxId,
8
- generateSlug
9
- } from "./chunk-QLL3W74D.js";
8
+ generateSlug,
9
+ writeWorkflowArtifact
10
+ } from "./chunk-VUASEQOQ.js";
10
11
  import "./chunk-Y55L47HC.js";
11
12
  export {
12
13
  SANDBOX_DIRS,
@@ -14,5 +15,6 @@ export {
14
15
  createSandboxDirectories,
15
16
  generateRandomSuffix,
16
17
  generateSandboxId,
17
- generateSlug
18
+ generateSlug,
19
+ writeWorkflowArtifact
18
20
  };
@@ -2,14 +2,14 @@
2
2
  import {
3
3
  syncRegistrySources,
4
4
  syncSource
5
- } from "./chunk-HMJDIX7C.js";
5
+ } from "./chunk-QQGRKUSM.js";
6
6
  import "./chunk-XTUQVJYH.js";
7
7
  import "./chunk-VRBGWKZ6.js";
8
8
  import {
9
9
  init_esm_shims
10
10
  } from "./chunk-Y55L47HC.js";
11
11
 
12
- // ../../packages/provider/dist/sync-MFM46YAB.js
12
+ // ../../packages/provider/dist/sync-E5PGFGNI.js
13
13
  init_esm_shims();
14
14
  export {
15
15
  syncRegistrySources,
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@looplia/looplia-cli",
3
- "version": "0.7.2",
3
+ "version": "0.7.3",
4
4
  "description": "Looplia CLI - AI-powered workflow automation tool",
5
5
  "type": "module",
6
6
  "license": "Elastic-2.0",
@@ -113,17 +113,17 @@ Before executing a step, validate:
113
113
  ### Input-less Capable Skills
114
114
 
115
115
  These skills can operate without an `input` field:
116
- - `search` - Executes search missions autonomously
116
+ - `browser-research` - Executes research missions autonomously (from looplia-skills)
117
117
 
118
118
  Example input-less step:
119
119
  ```yaml
120
120
  - id: find-news
121
- skill: search
121
+ skill: browser-research
122
122
  mission: |
123
123
  Search Hacker News for today's top 3 AI stories.
124
124
  Extract title, URL, points, and brief summary.
125
125
  output: ${{ sandbox }}/outputs/news.json
126
- # No input field - search operates autonomously
126
+ # No input field - browser-research operates autonomously
127
127
  ```
128
128
 
129
129
  ---
@@ -108,12 +108,12 @@ These skills can operate WITHOUT an input field - they fetch/generate data auton
108
108
  **Example input-less first step:**
109
109
  ```yaml
110
110
  - id: fetch-data
111
- skill: search
111
+ skill: browser-research
112
112
  mission: |
113
113
  Search the web for recent technology trends.
114
114
  Extract titles, URLs, and key details.
115
115
  output: ${{ sandbox }}/outputs/data.json
116
- # NO input field - search operates autonomously
116
+ # NO input field - browser-research operates autonomously
117
117
  ```
118
118
 
119
119
  ### Step 5: Suggest Validation
@@ -196,15 +196,21 @@ No input required - this workflow uses autonomous skills to fetch data.
196
196
 
197
197
  ## Output Format
198
198
 
199
- Return a JSON object:
199
+ Return a JSON object (v0.7.3: used by CLI for artifact persistence):
200
200
 
201
201
  ```json
202
202
  {
203
203
  "filename": "video-to-blog.md",
204
- "content": "---\nname: video-to-blog\n..."
204
+ "content": "---\nname: video-to-blog\nversion: 1.0.0\n...\n---\n\n# Video to Blog Workflow\n..."
205
205
  }
206
206
  ```
207
207
 
208
+ **Important**: `content` MUST be the complete, ready-to-write markdown file including:
209
+ - Full YAML frontmatter (between `---` delimiters)
210
+ - Markdown body (usage docs, steps section)
211
+
212
+ The CLI writes this content directly to `{workspace}/workflows/{filename}`.
213
+
208
214
  ## Schema Reference
209
215
 
210
216
  See SCHEMA.md in this skill directory for the complete v0.6.2 workflow schema.
@@ -313,17 +319,17 @@ description: Fetch trending news and compile a digest report
313
319
 
314
320
  # v0.7.0: Explicit skills declaration
315
321
  skills:
316
- - search
322
+ - browser-research
317
323
  - content-documenter
318
324
 
319
325
  steps:
320
326
  - id: fetch-news
321
- skill: search
327
+ skill: browser-research
322
328
  mission: |
323
329
  Search the web for today's trending technology news.
324
330
  Extract title, URL, source, and brief summary for each story.
325
331
  output: ${{ sandbox }}/outputs/news.json
326
- # NO input field - search operates autonomously
332
+ # NO input field - browser-research operates autonomously
327
333
  validate:
328
334
  required_fields: [query, mode, results]
329
335
 
@@ -368,7 +374,7 @@ Given enriched prompt:
368
374
  **BAD workflow (ignores preferences):**
369
375
  ```yaml
370
376
  - id: fetch-news
371
- skill: search
377
+ skill: browser-research
372
378
  mission: |
373
379
  Search HackerNews for AI news articles.
374
380
  Extract titles and summaries.
@@ -382,7 +388,7 @@ Given enriched prompt:
382
388
  **GOOD workflow (incorporates preferences):**
383
389
  ```yaml
384
390
  - id: fetch-news
385
- skill: search
391
+ skill: browser-research
386
392
  mission: |
387
393
  Search HackerNews for the top 5 AI news articles
388
394
  focusing on LLM developments and adoption trends.
@@ -1,174 +0,0 @@
1
- ---
2
- name: search
3
- description: |
4
- This skill should be used when the user needs to search for information, find files,
5
- look up content online, or retrieve data without providing input files.
6
-
7
- Trigger phrases include:
8
- - "search for", "find", "look up", "research"
9
- - "search the web", "search online", "fetch from URL"
10
- - "search files", "scan codebase", "find in project", "grep for"
11
- - "get news from", "read hacker news", "check what's trending"
12
-
13
- Supports multiple search modes:
14
- - local: Search local filesystem using Glob, Grep, Read, Bash
15
- - web: Search web content using WebSearch, WebFetch
16
- - future: Pluggable providers (jina.ai, firecrawl, exa.ai)
17
-
18
- This is an input-less skill - it executes search missions autonomously.
19
- model: haiku
20
- tools:
21
- - Glob
22
- - Grep
23
- - Read
24
- - Bash
25
- - WebSearch
26
- - WebFetch
27
- ---
28
-
29
- # Search Skill
30
-
31
- Execute search missions and compile structured results from various sources.
32
-
33
- ## Purpose
34
-
35
- Provide a unified search interface that can:
36
- 1. Search local files, codebases, and directories
37
- 2. Search web content (via WebSearch/WebFetch or future provider integrations)
38
- 3. Compile results into structured JSON output
39
-
40
- This skill operates **without user-provided input files** - it receives a search mission and executes it autonomously.
41
-
42
- ## Search Modes
43
-
44
- ### Local Mode
45
-
46
- Search the local environment:
47
-
48
- | Tool | Use Case |
49
- |------|----------|
50
- | `Glob` | Find files by pattern (e.g., `**/*.md`, `src/**/*.ts`) |
51
- | `Grep` | Search file contents for patterns |
52
- | `Read` | Read matched files for content extraction |
53
- | `Bash` | Execute find, ls, or other search commands |
54
-
55
- ### Web Mode
56
-
57
- Search web content:
58
-
59
- | Tool | Use Case |
60
- |------|----------|
61
- | `WebSearch` | Search the web for topics, news, documentation |
62
- | `WebFetch` | Fetch and extract content from URLs |
63
-
64
- **Future Providers** (planned integration):
65
- - `jina.ai` - AI-powered web search and extraction
66
- - `firecrawl` - Web crawling and scraping
67
- - `exa.ai` - Neural search engine
68
-
69
- ## Process
70
-
71
- ### Step 1: Parse Mission
72
-
73
- Extract from the mission description:
74
- - **Search target**: What to search for (keywords, patterns, topics)
75
- - **Search mode**: local, web, or auto-detect
76
- - **Scope**: Directories, file types, domains, date range
77
- - **Compile format**: How to structure results
78
-
79
- ### Step 2: Execute Search
80
-
81
- Based on mode:
82
-
83
- **Local:**
84
- ```
85
- 1. Use Glob to find matching files
86
- 2. Use Grep to search content patterns
87
- 3. Use Read to extract relevant sections
88
- 4. Compile matched results
89
- ```
90
-
91
- **Web:**
92
- ```
93
- 1. Use WebSearch to find relevant pages
94
- 2. Use WebFetch to extract content
95
- 3. Parse and filter results
96
- 4. Compile into structured format
97
- ```
98
-
99
- ### Step 3: Compile Results
100
-
101
- Structure findings into the output schema with:
102
- - Source attribution (file path or URL)
103
- - Relevance scoring
104
- - Extracted content snippets
105
- - Metadata (date, author if available)
106
-
107
- ## Input
108
-
109
- The skill receives a **mission description** specifying:
110
- - What to search for
111
- - Where to search (mode/scope)
112
- - What to extract and compile
113
-
114
- Example missions:
115
- ```
116
- Search for all TODO comments in the src/ directory and compile a list with file locations.
117
- ```
118
- ```
119
- Search Hacker News for the top 5 trending AI stories today and summarize each.
120
- ```
121
- ```
122
- Find all TypeScript files that import from '@looplia-core/core' and list their exports.
123
- ```
124
-
125
- ## Output Schema
126
-
127
- ```json
128
- {
129
- "query": "original search query/mission",
130
- "mode": "local | web",
131
- "results": [
132
- {
133
- "source": "path/to/file.ts | https://example.com/page",
134
- "type": "file | url",
135
- "title": "Optional title or filename",
136
- "content": "Extracted content or snippet",
137
- "relevance": 0.95,
138
- "metadata": {
139
- "lineNumber": 42,
140
- "matchContext": "surrounding context",
141
- "date": "2025-12-24",
142
- "author": "optional"
143
- }
144
- }
145
- ],
146
- "summary": "Brief summary of findings",
147
- "totalMatches": 15,
148
- "compiledAt": "2025-12-24T10:30:00Z"
149
- }
150
- ```
151
-
152
- ## Usage in Workflows
153
-
154
- This skill enables **input-less workflow steps**:
155
-
156
- ```yaml
157
- steps:
158
- - id: find-news
159
- skill: search
160
- mission: |
161
- Search Hacker News for today's top 3 AI stories.
162
- Extract title, URL, points, and brief summary for each.
163
- output: outputs/news.json
164
- ```
165
-
166
- No `input:` field required - the skill operates autonomously.
167
-
168
- ## Important Rules
169
-
170
- 1. **Always attribute sources** - Include file paths or URLs for all results
171
- 2. **Respect scope** - Only search within specified boundaries
172
- 3. **Compile, don't dump** - Structure results, don't return raw search output
173
- 4. **Handle empty results** - Return valid JSON even when no matches found
174
- 5. **Rate limit web searches** - Be mindful of API limits for web providers