@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.
- package/dist/{chunk-OIE7CSW6.js → chunk-MHR5TPHE.js} +4 -4
- package/dist/{chunk-HMJDIX7C.js → chunk-QQGRKUSM.js} +9 -1
- package/dist/{chunk-QLL3W74D.js → chunk-VUASEQOQ.js} +27 -2
- package/dist/{chunk-2ETB5RP7.js → chunk-VYGRYFSY.js} +4 -4
- package/dist/{claude-agent-sdk-YGNDVP55.js → claude-agent-sdk-SQ6YU4VE.js} +1 -1
- package/dist/cli.js +56 -27
- package/dist/{dist-3B4KUA76.js → dist-PMEIK6PJ.js} +3 -3
- package/dist/{sandbox-LD3EU4YO.js → sandbox-XVMNWAJO.js} +5 -3
- package/dist/{sync-MFM46YAB-SSBMNJ7D.js → sync-E5PGFGNI-IGGJR7IL.js} +2 -2
- package/package.json +1 -1
- package/plugins/looplia-core/skills/workflow-executor/SKILL.md +3 -3
- package/plugins/looplia-core/skills/workflow-schema-composer/SKILL.md +15 -9
- package/plugins/looplia-core/skills/search/SKILL.md +0 -174
|
@@ -7,7 +7,7 @@ import {
|
|
|
7
7
|
init_esm_shims
|
|
8
8
|
} from "./chunk-Y55L47HC.js";
|
|
9
9
|
|
|
10
|
-
// ../../packages/provider/dist/chunk-
|
|
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-
|
|
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-
|
|
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-
|
|
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-
|
|
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 {
|
|
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-
|
|
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 = ["
|
|
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-
|
|
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-
|
|
1039
|
+
const { syncSource: sync } = await import("./sync-E5PGFGNI-IGGJR7IL.js");
|
|
1040
1040
|
const result = await sync(source, {
|
|
1041
1041
|
showProgress,
|
|
1042
1042
|
skillPath
|
package/dist/cli.js
CHANGED
|
@@ -12,8 +12,8 @@ import {
|
|
|
12
12
|
removeSkill,
|
|
13
13
|
updateSkill,
|
|
14
14
|
validateUserProfile
|
|
15
|
-
} from "./chunk-
|
|
16
|
-
import "./chunk-
|
|
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-
|
|
45
|
+
} from "./chunk-MHR5TPHE.js";
|
|
46
46
|
import "./chunk-VRBGWKZ6.js";
|
|
47
47
|
import {
|
|
48
48
|
copyOutputsToDestination,
|
|
49
49
|
createSandboxDirectories,
|
|
50
|
-
generateSandboxId
|
|
51
|
-
|
|
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-
|
|
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-
|
|
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-
|
|
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-
|
|
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-
|
|
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
|
|
34284
|
-
if (result.
|
|
34285
|
-
console.
|
|
34286
|
-
|
|
34287
|
-
|
|
34288
|
-
|
|
34289
|
-
|
|
34290
|
-
|
|
34291
|
-
|
|
34292
|
-
|
|
34293
|
-
|
|
34294
|
-
|
|
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
|
-
|
|
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-
|
|
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.
|
|
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-
|
|
14
|
+
} from "./chunk-VYGRYFSY.js";
|
|
15
15
|
import {
|
|
16
16
|
syncRegistrySources,
|
|
17
17
|
syncSource
|
|
18
|
-
} from "./chunk-
|
|
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-
|
|
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
|
-
|
|
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-
|
|
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-
|
|
12
|
+
// ../../packages/provider/dist/sync-E5PGFGNI.js
|
|
13
13
|
init_esm_shims();
|
|
14
14
|
export {
|
|
15
15
|
syncRegistrySources,
|
package/package.json
CHANGED
|
@@ -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
|
-
- `
|
|
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:
|
|
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 -
|
|
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:
|
|
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 -
|
|
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
|
-
-
|
|
322
|
+
- browser-research
|
|
317
323
|
- content-documenter
|
|
318
324
|
|
|
319
325
|
steps:
|
|
320
326
|
- id: fetch-news
|
|
321
|
-
skill:
|
|
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 -
|
|
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:
|
|
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:
|
|
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
|