@looplia/looplia-cli 0.7.0 → 0.7.1
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-2TWYHMFD.js +1148 -0
- package/dist/chunk-5WPEFJ5J.js +42 -0
- package/dist/chunk-APZNHRV3.js +7 -0
- package/dist/{chunk-GN6D7YWI.js → chunk-DN3RSIIJ.js} +139 -124
- package/dist/{chunk-APETX7TD.js → chunk-HSZZVXV5.js} +2298 -8048
- package/dist/chunk-NUQVUYOZ.js +379 -0
- package/dist/{chunk-FCL2HRTX.js → chunk-VRBGWKZ6.js} +9 -19
- package/dist/chunk-Y55L47HC.js +61 -0
- package/dist/claude-agent-sdk-BKJ5OHH6.js +68 -0
- package/dist/cli.js +33319 -1750
- package/dist/{compiler-J4DARL4X-2TXNVYEY.js → compiler-4VFX7JAN-K3XYU5VB.js} +11 -3
- package/dist/devtools-MCPGSUKV.js +3713 -0
- package/dist/{dist-2ZDF6EID.js → dist-5SEP7KKQ.js} +16 -10
- package/dist/sandbox-HAMJNBZ6.js +16 -0
- package/dist/sync-MXQ4NJWI-KGAZYCPW.js +17 -0
- package/package.json +1 -1
- package/plugins/looplia-core/skills/registry-loader/SKILL.md +1 -1
- package/plugins/looplia-core/skills/search/SKILL.md +1 -1
- package/plugins/looplia-core/skills/skill-capability-matcher/SKILL.md +1 -1
- package/plugins/looplia-core/skills/workflow-schema-composer/SKILL.md +1 -1
- package/dist/chunk-IVTVHH75.js +0 -523
- package/dist/skill-installer-GJYXIKXE-VS4MWW3V.js +0 -18
- package/plugins/looplia-core/skills/plugin-registry-scanner/SKILL.md +0 -108
- package/plugins/looplia-core/skills/plugin-registry-scanner/scripts/scan-plugins.ts +0 -221
- package/plugins/looplia-core/skills/plugin-registry-scanner/test/scan-plugins.test.ts +0 -260
|
@@ -0,0 +1,42 @@
|
|
|
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,9 +1,13 @@
|
|
|
1
|
-
#!/usr/bin/env
|
|
1
|
+
#!/usr/bin/env bun
|
|
2
2
|
import {
|
|
3
3
|
pathExists
|
|
4
|
-
} from "./chunk-
|
|
4
|
+
} from "./chunk-VRBGWKZ6.js";
|
|
5
|
+
import {
|
|
6
|
+
init_esm_shims
|
|
7
|
+
} from "./chunk-Y55L47HC.js";
|
|
5
8
|
|
|
6
|
-
// ../../packages/provider/dist/chunk-
|
|
9
|
+
// ../../packages/provider/dist/chunk-M7EZUTK7.js
|
|
10
|
+
init_esm_shims();
|
|
7
11
|
import { exec } from "child_process";
|
|
8
12
|
import { mkdir, readdir, readFile, writeFile } from "fs/promises";
|
|
9
13
|
import { homedir } from "os";
|
|
@@ -26,6 +30,14 @@ function createProgress() {
|
|
|
26
30
|
console.log(`\u2713 ${message ?? currentMessage}`);
|
|
27
31
|
isActive = false;
|
|
28
32
|
},
|
|
33
|
+
warn(message) {
|
|
34
|
+
if (!isActive) {
|
|
35
|
+
return;
|
|
36
|
+
}
|
|
37
|
+
process.stdout.write("\r\x1B[K");
|
|
38
|
+
console.log(`\u26A0 ${message ?? currentMessage}`);
|
|
39
|
+
isActive = false;
|
|
40
|
+
},
|
|
29
41
|
fail(message) {
|
|
30
42
|
if (!isActive) {
|
|
31
43
|
return;
|
|
@@ -50,14 +62,6 @@ function createProgress() {
|
|
|
50
62
|
}
|
|
51
63
|
};
|
|
52
64
|
}
|
|
53
|
-
var execAsync = promisify(exec);
|
|
54
|
-
var OFFICIAL_REGISTRY_URL = "https://github.com/memorysaver/looplia-core/releases/latest/download/registry.json";
|
|
55
|
-
var REGISTRY_SCHEMA_URL = "https://looplia.com/schema/registry.json";
|
|
56
|
-
var REGISTRY_VERSION = "1.0.0";
|
|
57
|
-
var PROTOCOL_REGEX = /^https?:\/\//;
|
|
58
|
-
var TRAILING_SLASH_REGEX = /\/$/;
|
|
59
|
-
var LEADING_DOT_SLASH_REGEX = /^\.\//;
|
|
60
|
-
var FRONTMATTER_REGEX = /^---\n([\s\S]*?)\n---/;
|
|
61
65
|
var CAPABILITY_PATTERNS = [
|
|
62
66
|
{ pattern: /media|video|audio|image/, capability: "media-processing" },
|
|
63
67
|
{ pattern: /content|text|document/, capability: "content-analysis" },
|
|
@@ -67,6 +71,100 @@ var CAPABILITY_PATTERNS = [
|
|
|
67
71
|
{ pattern: /generat|creat|produc/, capability: "generation" },
|
|
68
72
|
{ pattern: /valid|check|verify/, capability: "validation" }
|
|
69
73
|
];
|
|
74
|
+
var FRONTMATTER_REGEX = /^---\n([\s\S]*?)\n---/;
|
|
75
|
+
var PROTOCOL_REGEX = /^https?:\/\//;
|
|
76
|
+
var TRAILING_SLASH_REGEX = /\/$/;
|
|
77
|
+
var LEADING_DOT_SLASH_REGEX = /^\.\//;
|
|
78
|
+
function parseMultilineValue(lines, startIndex) {
|
|
79
|
+
const multilineLines = [];
|
|
80
|
+
for (let j = startIndex; j < lines.length; j++) {
|
|
81
|
+
const nextLine = lines[j];
|
|
82
|
+
if (nextLine === void 0) {
|
|
83
|
+
break;
|
|
84
|
+
}
|
|
85
|
+
if (nextLine.startsWith(" ")) {
|
|
86
|
+
multilineLines.push(nextLine.trim());
|
|
87
|
+
} else if (nextLine.trim() !== "") {
|
|
88
|
+
break;
|
|
89
|
+
}
|
|
90
|
+
}
|
|
91
|
+
return multilineLines.join(" ");
|
|
92
|
+
}
|
|
93
|
+
function parseYamlFrontmatter(frontmatter) {
|
|
94
|
+
const lines = frontmatter.split("\n");
|
|
95
|
+
const metadata = {};
|
|
96
|
+
for (let i = 0; i < lines.length; i++) {
|
|
97
|
+
const line = lines[i];
|
|
98
|
+
if (line === void 0) {
|
|
99
|
+
continue;
|
|
100
|
+
}
|
|
101
|
+
const colonIndex = line.indexOf(":");
|
|
102
|
+
if (colonIndex <= 0) {
|
|
103
|
+
continue;
|
|
104
|
+
}
|
|
105
|
+
const key = line.slice(0, colonIndex).trim();
|
|
106
|
+
let value = line.slice(colonIndex + 1).trim();
|
|
107
|
+
if (value === "|") {
|
|
108
|
+
value = parseMultilineValue(lines, i + 1);
|
|
109
|
+
}
|
|
110
|
+
metadata[key] = value;
|
|
111
|
+
}
|
|
112
|
+
return metadata;
|
|
113
|
+
}
|
|
114
|
+
function inferCategory(name, description) {
|
|
115
|
+
const text = `${name} ${description}`.toLowerCase();
|
|
116
|
+
if (text.includes("review") || text.includes("analyze") || text.includes("scan")) {
|
|
117
|
+
return "analysis";
|
|
118
|
+
}
|
|
119
|
+
if (text.includes("generate") || text.includes("synthesis") || text.includes("create")) {
|
|
120
|
+
return "generation";
|
|
121
|
+
}
|
|
122
|
+
if (text.includes("assemble") || text.includes("document") || text.includes("compile")) {
|
|
123
|
+
return "assembly";
|
|
124
|
+
}
|
|
125
|
+
if (text.includes("validate") || text.includes("check")) {
|
|
126
|
+
return "validation";
|
|
127
|
+
}
|
|
128
|
+
if (text.includes("search") || text.includes("find")) {
|
|
129
|
+
return "search";
|
|
130
|
+
}
|
|
131
|
+
if (text.includes("workflow") || text.includes("execute") || text.includes("orchestrat")) {
|
|
132
|
+
return "orchestration";
|
|
133
|
+
}
|
|
134
|
+
return "utility";
|
|
135
|
+
}
|
|
136
|
+
function inferCapabilities(description) {
|
|
137
|
+
const capabilities = [];
|
|
138
|
+
const text = description.toLowerCase();
|
|
139
|
+
for (const { pattern, capability } of CAPABILITY_PATTERNS) {
|
|
140
|
+
if (pattern.test(text)) {
|
|
141
|
+
capabilities.push(capability);
|
|
142
|
+
}
|
|
143
|
+
}
|
|
144
|
+
return capabilities;
|
|
145
|
+
}
|
|
146
|
+
function formatTitle(name) {
|
|
147
|
+
return name.split("-").map((word) => word.charAt(0).toUpperCase() + word.slice(1)).join(" ");
|
|
148
|
+
}
|
|
149
|
+
var execAsync = promisify(exec);
|
|
150
|
+
var REGISTRY_VERSION = "1.0.0";
|
|
151
|
+
var DEFAULT_MARKETPLACE_SOURCES = [
|
|
152
|
+
{
|
|
153
|
+
name: "looplia-skills",
|
|
154
|
+
url: "https://github.com/memorysaver/looplia-skills",
|
|
155
|
+
description: "Looplia curated skills collection"
|
|
156
|
+
},
|
|
157
|
+
{
|
|
158
|
+
name: "anthropic-skills",
|
|
159
|
+
url: "https://github.com/anthropics/skills",
|
|
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
|
+
}
|
|
167
|
+
];
|
|
70
168
|
function getLoopliaHome() {
|
|
71
169
|
return process.env.LOOPLIA_HOME ?? join(homedir(), ".looplia");
|
|
72
170
|
}
|
|
@@ -86,16 +184,17 @@ async function initializeRegistry(force = false) {
|
|
|
86
184
|
await mkdir(registryPath, { recursive: true });
|
|
87
185
|
await mkdir(join(registryPath, "cache"), { recursive: true });
|
|
88
186
|
if (force || !await pathExists(sourcesPath)) {
|
|
89
|
-
const defaultSources =
|
|
90
|
-
{
|
|
91
|
-
id: "
|
|
92
|
-
type: "
|
|
93
|
-
url:
|
|
187
|
+
const defaultSources = DEFAULT_MARKETPLACE_SOURCES.map(
|
|
188
|
+
(source, index) => ({
|
|
189
|
+
id: `github:${source.url.replace("https://github.com/", "")}`,
|
|
190
|
+
type: "github",
|
|
191
|
+
url: source.url,
|
|
94
192
|
enabled: true,
|
|
95
|
-
priority:
|
|
193
|
+
priority: 90 - index * 10,
|
|
194
|
+
// First source gets highest priority
|
|
96
195
|
addedAt: (/* @__PURE__ */ new Date()).toISOString()
|
|
97
|
-
}
|
|
98
|
-
|
|
196
|
+
})
|
|
197
|
+
);
|
|
99
198
|
await writeFile(sourcesPath, JSON.stringify(defaultSources, null, 2));
|
|
100
199
|
}
|
|
101
200
|
}
|
|
@@ -168,7 +267,6 @@ async function tryFetchMarketplace(repoPath) {
|
|
|
168
267
|
}
|
|
169
268
|
}
|
|
170
269
|
return {
|
|
171
|
-
$schema: REGISTRY_SCHEMA_URL,
|
|
172
270
|
name: marketplace.name,
|
|
173
271
|
homepage: `https://github.com/${repoPath}`,
|
|
174
272
|
version: marketplace.version ?? "1.0.0",
|
|
@@ -192,24 +290,6 @@ async function tryFetchRegistryJson(repoPath) {
|
|
|
192
290
|
}
|
|
193
291
|
}
|
|
194
292
|
async function fetchRemoteRegistry(source) {
|
|
195
|
-
if (source.type === "official") {
|
|
196
|
-
try {
|
|
197
|
-
const response = await fetch(source.url);
|
|
198
|
-
if (!response.ok) {
|
|
199
|
-
console.warn(
|
|
200
|
-
`Failed to fetch registry from ${source.url}: ${response.status}`
|
|
201
|
-
);
|
|
202
|
-
return null;
|
|
203
|
-
}
|
|
204
|
-
return {
|
|
205
|
-
manifest: await response.json(),
|
|
206
|
-
format: "registry"
|
|
207
|
-
};
|
|
208
|
-
} catch (error) {
|
|
209
|
-
console.warn(`Error fetching registry from ${source.url}:`, error);
|
|
210
|
-
return null;
|
|
211
|
-
}
|
|
212
|
-
}
|
|
213
293
|
const repoPath = source.url.replace(PROTOCOL_REGEX, "").replace("github.com/", "").replace(TRAILING_SLASH_REGEX, "");
|
|
214
294
|
const marketplaceManifest = await tryFetchMarketplace(repoPath);
|
|
215
295
|
if (marketplaceManifest) {
|
|
@@ -224,42 +304,6 @@ async function fetchRemoteRegistry(source) {
|
|
|
224
304
|
);
|
|
225
305
|
return null;
|
|
226
306
|
}
|
|
227
|
-
function parseYamlFrontmatter(frontmatter) {
|
|
228
|
-
const lines = frontmatter.split("\n");
|
|
229
|
-
const metadata = {};
|
|
230
|
-
for (let i = 0; i < lines.length; i++) {
|
|
231
|
-
const line = lines[i];
|
|
232
|
-
if (line === void 0) {
|
|
233
|
-
continue;
|
|
234
|
-
}
|
|
235
|
-
const colonIndex = line.indexOf(":");
|
|
236
|
-
if (colonIndex <= 0) {
|
|
237
|
-
continue;
|
|
238
|
-
}
|
|
239
|
-
const key = line.slice(0, colonIndex).trim();
|
|
240
|
-
let value = line.slice(colonIndex + 1).trim();
|
|
241
|
-
if (value === "|") {
|
|
242
|
-
value = parseMultilineValue(lines, i + 1);
|
|
243
|
-
}
|
|
244
|
-
metadata[key] = value;
|
|
245
|
-
}
|
|
246
|
-
return metadata;
|
|
247
|
-
}
|
|
248
|
-
function parseMultilineValue(lines, startIndex) {
|
|
249
|
-
const multilineLines = [];
|
|
250
|
-
for (let j = startIndex; j < lines.length; j++) {
|
|
251
|
-
const nextLine = lines[j];
|
|
252
|
-
if (nextLine === void 0) {
|
|
253
|
-
break;
|
|
254
|
-
}
|
|
255
|
-
if (nextLine.startsWith(" ")) {
|
|
256
|
-
multilineLines.push(nextLine.trim());
|
|
257
|
-
} else if (nextLine.trim() !== "") {
|
|
258
|
-
break;
|
|
259
|
-
}
|
|
260
|
-
}
|
|
261
|
-
return multilineLines.join(" ");
|
|
262
|
-
}
|
|
263
307
|
function buildSkillFromMetadata(metadata) {
|
|
264
308
|
const category = inferCategory(
|
|
265
309
|
metadata.name ?? "",
|
|
@@ -294,41 +338,6 @@ async function parseSkillMetadata(skillPath) {
|
|
|
294
338
|
return null;
|
|
295
339
|
}
|
|
296
340
|
}
|
|
297
|
-
function inferCategory(name, description) {
|
|
298
|
-
const text = `${name} ${description}`.toLowerCase();
|
|
299
|
-
if (text.includes("review") || text.includes("analyze") || text.includes("scan")) {
|
|
300
|
-
return "analysis";
|
|
301
|
-
}
|
|
302
|
-
if (text.includes("generate") || text.includes("synthesis") || text.includes("create")) {
|
|
303
|
-
return "generation";
|
|
304
|
-
}
|
|
305
|
-
if (text.includes("assemble") || text.includes("document") || text.includes("compile")) {
|
|
306
|
-
return "assembly";
|
|
307
|
-
}
|
|
308
|
-
if (text.includes("validate") || text.includes("check")) {
|
|
309
|
-
return "validation";
|
|
310
|
-
}
|
|
311
|
-
if (text.includes("search") || text.includes("find")) {
|
|
312
|
-
return "search";
|
|
313
|
-
}
|
|
314
|
-
if (text.includes("workflow") || text.includes("execute") || text.includes("orchestrat")) {
|
|
315
|
-
return "orchestration";
|
|
316
|
-
}
|
|
317
|
-
return "utility";
|
|
318
|
-
}
|
|
319
|
-
function inferCapabilities(description) {
|
|
320
|
-
const capabilities = [];
|
|
321
|
-
const text = description.toLowerCase();
|
|
322
|
-
for (const { pattern, capability } of CAPABILITY_PATTERNS) {
|
|
323
|
-
if (pattern.test(text)) {
|
|
324
|
-
capabilities.push(capability);
|
|
325
|
-
}
|
|
326
|
-
}
|
|
327
|
-
return capabilities;
|
|
328
|
-
}
|
|
329
|
-
function formatTitle(name) {
|
|
330
|
-
return name.split("-").map((word) => word.charAt(0).toUpperCase() + word.slice(1)).join(" ");
|
|
331
|
-
}
|
|
332
341
|
async function getGitRemoteUrl(repoPath) {
|
|
333
342
|
const pluginJsonPath = join(repoPath, ".claude-plugin", "plugin.json");
|
|
334
343
|
try {
|
|
@@ -481,10 +490,10 @@ async function processRemoteSource(options) {
|
|
|
481
490
|
model: item.model,
|
|
482
491
|
inputless: item.inputless,
|
|
483
492
|
source: source.id,
|
|
484
|
-
sourceType:
|
|
493
|
+
sourceType: "thirdparty",
|
|
485
494
|
installed: installed !== void 0,
|
|
486
495
|
installedPath: installed?.installedPath,
|
|
487
|
-
gitUrl:
|
|
496
|
+
gitUrl: item.downloadUrl,
|
|
488
497
|
skillPath: item.skillPath,
|
|
489
498
|
// Set by marketplace format, undefined for registry.json
|
|
490
499
|
checksum: item.checksum,
|
|
@@ -516,7 +525,8 @@ function buildRegistrySummary(skills) {
|
|
|
516
525
|
}
|
|
517
526
|
return { byCategory, bySource };
|
|
518
527
|
}
|
|
519
|
-
async function compileRegistry(
|
|
528
|
+
async function compileRegistry(options) {
|
|
529
|
+
const { showProgress = false, localOnly = true } = options ?? {};
|
|
520
530
|
const progress = showProgress ? createProgress() : null;
|
|
521
531
|
const loopliaPath = getLoopliaHome();
|
|
522
532
|
const sources = await loadSources();
|
|
@@ -530,15 +540,17 @@ async function compileRegistry(showProgress = false) {
|
|
|
530
540
|
for (const source of localSources) {
|
|
531
541
|
await processLocalSource(source, seenSkills, allSkills, progress);
|
|
532
542
|
}
|
|
533
|
-
|
|
534
|
-
|
|
535
|
-
|
|
536
|
-
|
|
537
|
-
|
|
538
|
-
|
|
539
|
-
|
|
540
|
-
|
|
541
|
-
|
|
543
|
+
if (!localOnly) {
|
|
544
|
+
const remoteSources = sources.filter((s) => s.enabled && s.type !== "local").sort((a, b) => b.priority - a.priority);
|
|
545
|
+
for (const source of remoteSources) {
|
|
546
|
+
await processRemoteSource({
|
|
547
|
+
source,
|
|
548
|
+
seenSkills,
|
|
549
|
+
allSkills,
|
|
550
|
+
installedSkillsMap,
|
|
551
|
+
progress
|
|
552
|
+
});
|
|
553
|
+
}
|
|
542
554
|
}
|
|
543
555
|
const { byCategory, bySource } = buildRegistrySummary(allSkills);
|
|
544
556
|
const compiled = {
|
|
@@ -555,10 +567,9 @@ async function compileRegistry(showProgress = false) {
|
|
|
555
567
|
}
|
|
556
568
|
function createEmptyManifest() {
|
|
557
569
|
return {
|
|
558
|
-
|
|
559
|
-
name: "looplia-official",
|
|
570
|
+
name: "looplia",
|
|
560
571
|
homepage: "https://github.com/memorysaver/looplia-core",
|
|
561
|
-
version: "0.7.
|
|
572
|
+
version: "0.7.1",
|
|
562
573
|
updatedAt: (/* @__PURE__ */ new Date()).toISOString(),
|
|
563
574
|
items: []
|
|
564
575
|
};
|
|
@@ -566,6 +577,10 @@ function createEmptyManifest() {
|
|
|
566
577
|
|
|
567
578
|
export {
|
|
568
579
|
createProgress,
|
|
580
|
+
FRONTMATTER_REGEX,
|
|
581
|
+
PROTOCOL_REGEX,
|
|
582
|
+
TRAILING_SLASH_REGEX,
|
|
583
|
+
DEFAULT_MARKETPLACE_SOURCES,
|
|
569
584
|
getRegistryPath,
|
|
570
585
|
getCompiledRegistryPath,
|
|
571
586
|
getSkillCatalogPath,
|