@looplia/looplia-cli 0.7.1 → 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-HSZZVXV5.js → chunk-MHR5TPHE.js} +5 -5
- package/dist/{chunk-NUQVUYOZ.js → chunk-QQGRKUSM.js} +10 -2
- package/dist/chunk-VUASEQOQ.js +99 -0
- package/dist/{chunk-2TWYHMFD.js → chunk-VYGRYFSY.js} +5 -5
- package/dist/{chunk-DN3RSIIJ.js → chunk-XTUQVJYH.js} +1 -6
- package/dist/{claude-agent-sdk-BKJ5OHH6.js → claude-agent-sdk-SQ6YU4VE.js} +1 -1
- package/dist/cli.js +82 -29
- package/dist/{compiler-4VFX7JAN-K3XYU5VB.js → compiler-4B63UTUP-VE77VSJ2.js} +2 -2
- package/dist/{dist-5SEP7KKQ.js → dist-PMEIK6PJ.js} +4 -4
- package/dist/{sandbox-HAMJNBZ6.js → sandbox-XVMNWAJO.js} +7 -3
- package/dist/{sync-MXQ4NJWI-KGAZYCPW.js → sync-E5PGFGNI-IGGJR7IL.js} +3 -3
- 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/dist/chunk-5WPEFJ5J.js +0 -42
- 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 {
|
|
@@ -173,9 +173,9 @@ async function copyPlugins(targetDir, sourcePath) {
|
|
|
173
173
|
JSON.stringify(createDefaultProfile(), null, 2),
|
|
174
174
|
"utf-8"
|
|
175
175
|
);
|
|
176
|
-
const { initializeRegistry, compileRegistry } = await import("./compiler-
|
|
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";
|
|
@@ -5,7 +5,7 @@ import {
|
|
|
5
5
|
TRAILING_SLASH_REGEX,
|
|
6
6
|
createProgress,
|
|
7
7
|
loadSources
|
|
8
|
-
} from "./chunk-
|
|
8
|
+
} from "./chunk-XTUQVJYH.js";
|
|
9
9
|
import {
|
|
10
10
|
isValidGitUrl,
|
|
11
11
|
isValidPathSegment,
|
|
@@ -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({
|
|
@@ -0,0 +1,99 @@
|
|
|
1
|
+
#!/usr/bin/env bun
|
|
2
|
+
import {
|
|
3
|
+
init_esm_shims
|
|
4
|
+
} from "./chunk-Y55L47HC.js";
|
|
5
|
+
|
|
6
|
+
// src/utils/sandbox.ts
|
|
7
|
+
init_esm_shims();
|
|
8
|
+
import { randomBytes } from "crypto";
|
|
9
|
+
import {
|
|
10
|
+
copyFileSync,
|
|
11
|
+
existsSync,
|
|
12
|
+
mkdirSync,
|
|
13
|
+
readdirSync,
|
|
14
|
+
writeFileSync
|
|
15
|
+
} from "fs";
|
|
16
|
+
import { join, resolve } from "path";
|
|
17
|
+
var SANDBOX_DIRS = {
|
|
18
|
+
INPUTS: "inputs",
|
|
19
|
+
OUTPUTS: "outputs",
|
|
20
|
+
LOGS: "logs"
|
|
21
|
+
};
|
|
22
|
+
function generateRandomSuffix() {
|
|
23
|
+
return randomBytes(2).toString("hex");
|
|
24
|
+
}
|
|
25
|
+
function generateSlug(input, maxLength = 30) {
|
|
26
|
+
return input.toLowerCase().replace(/[^a-z0-9]+/g, "-").replace(/^-|-$/g, "").substring(0, maxLength);
|
|
27
|
+
}
|
|
28
|
+
function generateSandboxId(slug) {
|
|
29
|
+
const normalizedSlug = generateSlug(slug);
|
|
30
|
+
const date = (/* @__PURE__ */ new Date()).toISOString().split("T")[0];
|
|
31
|
+
const suffix = generateRandomSuffix();
|
|
32
|
+
return `${normalizedSlug}-${date}-${suffix}`;
|
|
33
|
+
}
|
|
34
|
+
function createSandboxDirectories(workspace, sandboxId) {
|
|
35
|
+
const sandboxDir = join(workspace, "sandbox", sandboxId);
|
|
36
|
+
mkdirSync(join(sandboxDir, SANDBOX_DIRS.INPUTS), { recursive: true });
|
|
37
|
+
mkdirSync(join(sandboxDir, SANDBOX_DIRS.OUTPUTS), { recursive: true });
|
|
38
|
+
mkdirSync(join(sandboxDir, SANDBOX_DIRS.LOGS), { recursive: true });
|
|
39
|
+
return sandboxDir;
|
|
40
|
+
}
|
|
41
|
+
function copyOutputsToDestination(workspace, sandboxId, destDir) {
|
|
42
|
+
if (!(workspace && sandboxId && destDir)) {
|
|
43
|
+
return 0;
|
|
44
|
+
}
|
|
45
|
+
const outputsPath = join(
|
|
46
|
+
workspace,
|
|
47
|
+
"sandbox",
|
|
48
|
+
sandboxId,
|
|
49
|
+
SANDBOX_DIRS.OUTPUTS
|
|
50
|
+
);
|
|
51
|
+
const resolvedDest = resolve(destDir);
|
|
52
|
+
mkdirSync(resolvedDest, { recursive: true });
|
|
53
|
+
let copiedCount = 0;
|
|
54
|
+
try {
|
|
55
|
+
const entries = readdirSync(outputsPath, { withFileTypes: true });
|
|
56
|
+
for (const entry of entries) {
|
|
57
|
+
if (entry.isFile()) {
|
|
58
|
+
const srcPath = join(outputsPath, entry.name);
|
|
59
|
+
const destPath = join(resolvedDest, entry.name);
|
|
60
|
+
copyFileSync(srcPath, destPath);
|
|
61
|
+
copiedCount += 1;
|
|
62
|
+
}
|
|
63
|
+
}
|
|
64
|
+
} catch (error) {
|
|
65
|
+
const nodeError = error;
|
|
66
|
+
if (nodeError.code !== "ENOENT") {
|
|
67
|
+
console.warn(`Warning: Error copying outputs: ${error}`);
|
|
68
|
+
}
|
|
69
|
+
}
|
|
70
|
+
return copiedCount;
|
|
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
|
+
}
|
|
90
|
+
|
|
91
|
+
export {
|
|
92
|
+
SANDBOX_DIRS,
|
|
93
|
+
generateRandomSuffix,
|
|
94
|
+
generateSlug,
|
|
95
|
+
generateSandboxId,
|
|
96
|
+
createSandboxDirectories,
|
|
97
|
+
copyOutputsToDestination,
|
|
98
|
+
writeWorkflowArtifact
|
|
99
|
+
};
|
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
import {
|
|
3
3
|
compileRegistry,
|
|
4
4
|
getCompiledRegistryPath
|
|
5
|
-
} from "./chunk-
|
|
5
|
+
} from "./chunk-XTUQVJYH.js";
|
|
6
6
|
import {
|
|
7
7
|
BRAND,
|
|
8
8
|
DIRTY,
|
|
@@ -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
|
|
@@ -6,7 +6,7 @@ import {
|
|
|
6
6
|
init_esm_shims
|
|
7
7
|
} from "./chunk-Y55L47HC.js";
|
|
8
8
|
|
|
9
|
-
// ../../packages/provider/dist/chunk-
|
|
9
|
+
// ../../packages/provider/dist/chunk-QHAUYGWN.js
|
|
10
10
|
init_esm_shims();
|
|
11
11
|
import { exec } from "child_process";
|
|
12
12
|
import { mkdir, readdir, readFile, writeFile } from "fs/promises";
|
|
@@ -158,11 +158,6 @@ var DEFAULT_MARKETPLACE_SOURCES = [
|
|
|
158
158
|
name: "anthropic-skills",
|
|
159
159
|
url: "https://github.com/anthropics/skills",
|
|
160
160
|
description: "Official Anthropic skills - xlsx, pdf, pptx, docx, frontend-design, and more"
|
|
161
|
-
},
|
|
162
|
-
{
|
|
163
|
-
name: "awesome-claude-skills",
|
|
164
|
-
url: "https://github.com/ComposioHQ/awesome-claude-skills",
|
|
165
|
-
description: "Community-curated Claude skills collection by ComposioHQ"
|
|
166
161
|
}
|
|
167
162
|
];
|
|
168
163
|
function getLoopliaHome() {
|
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,
|
|
@@ -21,7 +21,7 @@ import {
|
|
|
21
21
|
initializeRegistry,
|
|
22
22
|
loadSources,
|
|
23
23
|
removeSource
|
|
24
|
-
} from "./chunk-
|
|
24
|
+
} from "./chunk-XTUQVJYH.js";
|
|
25
25
|
import "./chunk-APZNHRV3.js";
|
|
26
26
|
import {
|
|
27
27
|
DEFAULT_SETTINGS,
|
|
@@ -42,12 +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
|
+
copyOutputsToDestination,
|
|
48
49
|
createSandboxDirectories,
|
|
49
|
-
generateSandboxId
|
|
50
|
-
|
|
50
|
+
generateSandboxId,
|
|
51
|
+
writeWorkflowArtifact
|
|
52
|
+
} from "./chunk-VUASEQOQ.js";
|
|
51
53
|
import {
|
|
52
54
|
__commonJS,
|
|
53
55
|
__dirname,
|
|
@@ -32863,10 +32865,10 @@ var ANALYSIS_RESULT_SCHEMA = {
|
|
|
32863
32865
|
}
|
|
32864
32866
|
};
|
|
32865
32867
|
async function* analyzeDescriptionStreaming(description, workspace, questionCallback) {
|
|
32866
|
-
const { createSandboxDirectories: createSandboxDirectories2, generateSandboxId: generateSandboxId2 } = await import("./sandbox-
|
|
32868
|
+
const { createSandboxDirectories: createSandboxDirectories2, generateSandboxId: generateSandboxId2 } = await import("./sandbox-XVMNWAJO.js");
|
|
32867
32869
|
const sandboxId = generateSandboxId2("build");
|
|
32868
32870
|
createSandboxDirectories2(workspace, sandboxId);
|
|
32869
|
-
const { executeInteractiveQueryStreaming } = await import("./claude-agent-sdk-
|
|
32871
|
+
const { executeInteractiveQueryStreaming } = await import("./claude-agent-sdk-SQ6YU4VE.js");
|
|
32870
32872
|
const prompt = `${buildAnalysisPrompt(description)} --sandbox-id ${sandboxId}`;
|
|
32871
32873
|
const generator = executeInteractiveQueryStreaming(
|
|
32872
32874
|
prompt,
|
|
@@ -34111,7 +34113,7 @@ function executeMock(args) {
|
|
|
34111
34113
|
}
|
|
34112
34114
|
async function executeBatch(prompt, workspace, executor) {
|
|
34113
34115
|
console.error("\u23F3 Building workflow...");
|
|
34114
|
-
const { createSandboxDirectories: createSandboxDirectories2, generateSandboxId: generateSandboxId2 } = await import("./sandbox-
|
|
34116
|
+
const { createSandboxDirectories: createSandboxDirectories2, generateSandboxId: generateSandboxId2 } = await import("./sandbox-XVMNWAJO.js");
|
|
34115
34117
|
const sandboxId = generateSandboxId2("build");
|
|
34116
34118
|
createSandboxDirectories2(workspace, sandboxId);
|
|
34117
34119
|
const promptWithSandbox = `${prompt} --sandbox-id ${sandboxId}`;
|
|
@@ -34129,11 +34131,11 @@ async function executeBatch(prompt, workspace, executor) {
|
|
|
34129
34131
|
};
|
|
34130
34132
|
}
|
|
34131
34133
|
async function* executeInteractiveStreamingBatch(prompt, workspace, questionCallback) {
|
|
34132
|
-
const { createSandboxDirectories: createSandboxDirectories2, generateSandboxId: generateSandboxId2 } = await import("./sandbox-
|
|
34134
|
+
const { createSandboxDirectories: createSandboxDirectories2, generateSandboxId: generateSandboxId2 } = await import("./sandbox-XVMNWAJO.js");
|
|
34133
34135
|
const sandboxId = generateSandboxId2("build");
|
|
34134
34136
|
createSandboxDirectories2(workspace, sandboxId);
|
|
34135
34137
|
const promptWithSandbox = `${prompt} --sandbox-id ${sandboxId}`;
|
|
34136
|
-
const { executeInteractiveQueryStreaming } = await import("./claude-agent-sdk-
|
|
34138
|
+
const { executeInteractiveQueryStreaming } = await import("./claude-agent-sdk-SQ6YU4VE.js");
|
|
34137
34139
|
const schema = {
|
|
34138
34140
|
type: "object",
|
|
34139
34141
|
properties: {
|
|
@@ -34279,24 +34281,52 @@ function executeBuild(prompt, workspace, parsed) {
|
|
|
34279
34281
|
}
|
|
34280
34282
|
return executeBatch(prompt, workspace);
|
|
34281
34283
|
}
|
|
34282
|
-
function
|
|
34283
|
-
if (result.
|
|
34284
|
-
console.
|
|
34285
|
-
|
|
34286
|
-
|
|
34287
|
-
|
|
34288
|
-
|
|
34289
|
-
|
|
34290
|
-
|
|
34291
|
-
|
|
34292
|
-
|
|
34293
|
-
|
|
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(`
|
|
34294
34313
|
Steps: ${result.stepsCount}`);
|
|
34295
|
-
|
|
34296
|
-
|
|
34314
|
+
}
|
|
34315
|
+
}
|
|
34316
|
+
function renderResult(result, workspace) {
|
|
34317
|
+
if (result.status !== "success") {
|
|
34297
34318
|
console.error(`
|
|
34298
34319
|
\u274C Build failed: ${result.error ?? "Unknown error"}`);
|
|
34320
|
+
return;
|
|
34299
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;
|
|
34327
|
+
}
|
|
34328
|
+
const displayPath = writtenPath ?? result.workflowPath ?? null;
|
|
34329
|
+
renderSuccessMessage(result, displayPath);
|
|
34300
34330
|
}
|
|
34301
34331
|
async function runBuildCommand(args) {
|
|
34302
34332
|
const parsed = parseArgs(args);
|
|
@@ -34315,7 +34345,7 @@ async function runBuildCommand(args) {
|
|
|
34315
34345
|
await initializeCommandEnvironment({ mock: parsed.mock });
|
|
34316
34346
|
const prompt = buildPrompt(parsed);
|
|
34317
34347
|
const result = await executeBuild(prompt, workspace, parsed);
|
|
34318
|
-
renderResult(result);
|
|
34348
|
+
renderResult(result, workspace);
|
|
34319
34349
|
if (result.status !== "success") {
|
|
34320
34350
|
process.exit(1);
|
|
34321
34351
|
}
|
|
@@ -35163,7 +35193,7 @@ function parseInputValue(value) {
|
|
|
35163
35193
|
return { type: "file", value };
|
|
35164
35194
|
}
|
|
35165
35195
|
function isValueFlag2(arg) {
|
|
35166
|
-
return arg === "--file" || arg === "-f" || arg === "--input" || arg === "-i" || arg === "--sandbox" || arg === "-s" || arg === "--sandbox-id";
|
|
35196
|
+
return arg === "--file" || arg === "-f" || arg === "--input" || arg === "-i" || arg === "--output" || arg === "-o" || arg === "--sandbox" || arg === "-s" || arg === "--sandbox-id";
|
|
35167
35197
|
}
|
|
35168
35198
|
function parseInputArg(value) {
|
|
35169
35199
|
const equalsIndex = value.indexOf("=");
|
|
@@ -35212,6 +35242,10 @@ function processArg2(result, arg, nextArg) {
|
|
|
35212
35242
|
case "-s":
|
|
35213
35243
|
result.sandboxId = nextArg;
|
|
35214
35244
|
break;
|
|
35245
|
+
case "--output":
|
|
35246
|
+
case "-o":
|
|
35247
|
+
result.output = nextArg;
|
|
35248
|
+
break;
|
|
35215
35249
|
case "--mock":
|
|
35216
35250
|
result.mock = true;
|
|
35217
35251
|
break;
|
|
@@ -35258,6 +35292,8 @@ Options:
|
|
|
35258
35292
|
--file, -f <path> Path to content file (creates new sandbox, legacy)
|
|
35259
35293
|
--input, -i <name=value> Named input (can specify multiple times)
|
|
35260
35294
|
Value can be a file path or inline JSON
|
|
35295
|
+
--output, -o <dir> Copy outputs to this directory (default: cwd)
|
|
35296
|
+
Also supports LOOPLIA_OUTPUT_DIR env var
|
|
35261
35297
|
--sandbox-id, -s <id> Resume existing sandbox
|
|
35262
35298
|
--mock Use mock mode (no API calls)
|
|
35263
35299
|
--no-streaming Disable streaming output
|
|
@@ -35278,6 +35314,9 @@ Examples:
|
|
|
35278
35314
|
|
|
35279
35315
|
# Resume existing sandbox
|
|
35280
35316
|
looplia run writing-kit --sandbox-id text-2025-12-18-abc123
|
|
35317
|
+
|
|
35318
|
+
# Copy outputs to specific directory (v0.7.2)
|
|
35319
|
+
looplia run writing-kit --file article.md --output ./results/
|
|
35281
35320
|
`);
|
|
35282
35321
|
}
|
|
35283
35322
|
function getWorkspacePath2() {
|
|
@@ -35432,6 +35471,16 @@ function renderResult2(result) {
|
|
|
35432
35471
|
\u274C Workflow failed: ${result.error ?? "Unknown error"}`);
|
|
35433
35472
|
}
|
|
35434
35473
|
}
|
|
35474
|
+
function handleOutputCopy(workspace, sandboxId, outputDir) {
|
|
35475
|
+
if (!outputDir) {
|
|
35476
|
+
return;
|
|
35477
|
+
}
|
|
35478
|
+
const copiedCount = copyOutputsToDestination(workspace, sandboxId, outputDir);
|
|
35479
|
+
if (copiedCount > 0) {
|
|
35480
|
+
console.log(`
|
|
35481
|
+
\u2713 ${copiedCount} output file(s) copied to ${outputDir}`);
|
|
35482
|
+
}
|
|
35483
|
+
}
|
|
35435
35484
|
async function handleJitInstallation(workflowInfo) {
|
|
35436
35485
|
if (!workflowInfo) {
|
|
35437
35486
|
return true;
|
|
@@ -35488,6 +35537,10 @@ async function runRunCommand(args) {
|
|
|
35488
35537
|
requiredSkills: workflowInfo?.skills
|
|
35489
35538
|
});
|
|
35490
35539
|
renderResult2(result);
|
|
35540
|
+
if (result.status === "success") {
|
|
35541
|
+
const outputDir = parsed.output || process.env.LOOPLIA_OUTPUT_DIR || process.cwd();
|
|
35542
|
+
handleOutputCopy(workspace, sandboxId, outputDir);
|
|
35543
|
+
}
|
|
35491
35544
|
if (result.status !== "success") {
|
|
35492
35545
|
process.exit(1);
|
|
35493
35546
|
}
|
|
@@ -35569,7 +35622,7 @@ async function skillAdd(nameOrUrl, from) {
|
|
|
35569
35622
|
}
|
|
35570
35623
|
if (GITHUB_URL_PATTERN.test(nameOrUrl)) {
|
|
35571
35624
|
console.log(`Installing skill from URL: ${nameOrUrl}...`);
|
|
35572
|
-
const { installSkillFromUrl } = await import("./dist-
|
|
35625
|
+
const { installSkillFromUrl } = await import("./dist-PMEIK6PJ.js");
|
|
35573
35626
|
const result2 = await installSkillFromUrl(nameOrUrl, true);
|
|
35574
35627
|
switch (result2.status) {
|
|
35575
35628
|
case "installed":
|
|
@@ -35806,7 +35859,7 @@ async function runSkillCommand(args) {
|
|
|
35806
35859
|
}
|
|
35807
35860
|
|
|
35808
35861
|
// src/index.ts
|
|
35809
|
-
var VERSION = "0.7.
|
|
35862
|
+
var VERSION = "0.7.3";
|
|
35810
35863
|
function printHelp5() {
|
|
35811
35864
|
console.log(`
|
|
35812
35865
|
looplia - Content intelligence CLI (v${VERSION})
|
|
@@ -12,13 +12,13 @@ import {
|
|
|
12
12
|
loadSources,
|
|
13
13
|
removeSource,
|
|
14
14
|
saveSources
|
|
15
|
-
} from "./chunk-
|
|
15
|
+
} from "./chunk-XTUQVJYH.js";
|
|
16
16
|
import "./chunk-VRBGWKZ6.js";
|
|
17
17
|
import {
|
|
18
18
|
init_esm_shims
|
|
19
19
|
} from "./chunk-Y55L47HC.js";
|
|
20
20
|
|
|
21
|
-
// ../../packages/provider/dist/compiler-
|
|
21
|
+
// ../../packages/provider/dist/compiler-4B63UTUP.js
|
|
22
22
|
init_esm_shims();
|
|
23
23
|
export {
|
|
24
24
|
DEFAULT_MARKETPLACE_SOURCES,
|
|
@@ -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,
|
|
@@ -27,12 +27,12 @@ import {
|
|
|
27
27
|
loadSources,
|
|
28
28
|
removeSource,
|
|
29
29
|
saveSources
|
|
30
|
-
} from "./chunk-
|
|
30
|
+
} from "./chunk-XTUQVJYH.js";
|
|
31
31
|
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 {
|
|
@@ -1,16 +1,20 @@
|
|
|
1
1
|
#!/usr/bin/env bun
|
|
2
2
|
import {
|
|
3
3
|
SANDBOX_DIRS,
|
|
4
|
+
copyOutputsToDestination,
|
|
4
5
|
createSandboxDirectories,
|
|
5
6
|
generateRandomSuffix,
|
|
6
7
|
generateSandboxId,
|
|
7
|
-
generateSlug
|
|
8
|
-
|
|
8
|
+
generateSlug,
|
|
9
|
+
writeWorkflowArtifact
|
|
10
|
+
} from "./chunk-VUASEQOQ.js";
|
|
9
11
|
import "./chunk-Y55L47HC.js";
|
|
10
12
|
export {
|
|
11
13
|
SANDBOX_DIRS,
|
|
14
|
+
copyOutputsToDestination,
|
|
12
15
|
createSandboxDirectories,
|
|
13
16
|
generateRandomSuffix,
|
|
14
17
|
generateSandboxId,
|
|
15
|
-
generateSlug
|
|
18
|
+
generateSlug,
|
|
19
|
+
writeWorkflowArtifact
|
|
16
20
|
};
|
|
@@ -2,14 +2,14 @@
|
|
|
2
2
|
import {
|
|
3
3
|
syncRegistrySources,
|
|
4
4
|
syncSource
|
|
5
|
-
} from "./chunk-
|
|
6
|
-
import "./chunk-
|
|
5
|
+
} from "./chunk-QQGRKUSM.js";
|
|
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.
|
package/dist/chunk-5WPEFJ5J.js
DELETED
|
@@ -1,42 +0,0 @@
|
|
|
1
|
-
#!/usr/bin/env bun
|
|
2
|
-
import {
|
|
3
|
-
init_esm_shims
|
|
4
|
-
} from "./chunk-Y55L47HC.js";
|
|
5
|
-
|
|
6
|
-
// src/utils/sandbox.ts
|
|
7
|
-
init_esm_shims();
|
|
8
|
-
import { randomBytes } from "crypto";
|
|
9
|
-
import { mkdirSync } from "fs";
|
|
10
|
-
import { join } from "path";
|
|
11
|
-
var SANDBOX_DIRS = {
|
|
12
|
-
INPUTS: "inputs",
|
|
13
|
-
OUTPUTS: "outputs",
|
|
14
|
-
LOGS: "logs"
|
|
15
|
-
};
|
|
16
|
-
function generateRandomSuffix() {
|
|
17
|
-
return randomBytes(2).toString("hex");
|
|
18
|
-
}
|
|
19
|
-
function generateSlug(input, maxLength = 30) {
|
|
20
|
-
return input.toLowerCase().replace(/[^a-z0-9]+/g, "-").replace(/^-|-$/g, "").substring(0, maxLength);
|
|
21
|
-
}
|
|
22
|
-
function generateSandboxId(slug) {
|
|
23
|
-
const normalizedSlug = generateSlug(slug);
|
|
24
|
-
const date = (/* @__PURE__ */ new Date()).toISOString().split("T")[0];
|
|
25
|
-
const suffix = generateRandomSuffix();
|
|
26
|
-
return `${normalizedSlug}-${date}-${suffix}`;
|
|
27
|
-
}
|
|
28
|
-
function createSandboxDirectories(workspace, sandboxId) {
|
|
29
|
-
const sandboxDir = join(workspace, "sandbox", sandboxId);
|
|
30
|
-
mkdirSync(join(sandboxDir, SANDBOX_DIRS.INPUTS), { recursive: true });
|
|
31
|
-
mkdirSync(join(sandboxDir, SANDBOX_DIRS.OUTPUTS), { recursive: true });
|
|
32
|
-
mkdirSync(join(sandboxDir, SANDBOX_DIRS.LOGS), { recursive: true });
|
|
33
|
-
return sandboxDir;
|
|
34
|
-
}
|
|
35
|
-
|
|
36
|
-
export {
|
|
37
|
-
SANDBOX_DIRS,
|
|
38
|
-
generateRandomSuffix,
|
|
39
|
-
generateSlug,
|
|
40
|
-
generateSandboxId,
|
|
41
|
-
createSandboxDirectories
|
|
42
|
-
};
|
|
@@ -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
|