squads 0.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/commands/add.d.ts +3 -0
- package/dist/commands/add.d.ts.map +1 -0
- package/dist/commands/add.js +98 -0
- package/dist/commands/add.js.map +1 -0
- package/dist/commands/check.d.ts +3 -0
- package/dist/commands/check.d.ts.map +1 -0
- package/dist/commands/check.js +127 -0
- package/dist/commands/check.js.map +1 -0
- package/dist/commands/find.d.ts +3 -0
- package/dist/commands/find.d.ts.map +1 -0
- package/dist/commands/find.js +84 -0
- package/dist/commands/find.js.map +1 -0
- package/dist/commands/init.d.ts +3 -0
- package/dist/commands/init.d.ts.map +1 -0
- package/dist/commands/init.js +281 -0
- package/dist/commands/init.js.map +1 -0
- package/dist/commands/list.d.ts +3 -0
- package/dist/commands/list.d.ts.map +1 -0
- package/dist/commands/list.js +49 -0
- package/dist/commands/list.js.map +1 -0
- package/dist/commands/login.d.ts +3 -0
- package/dist/commands/login.d.ts.map +1 -0
- package/dist/commands/login.js +129 -0
- package/dist/commands/login.js.map +1 -0
- package/dist/commands/publish.d.ts +3 -0
- package/dist/commands/publish.d.ts.map +1 -0
- package/dist/commands/publish.js +118 -0
- package/dist/commands/publish.js.map +1 -0
- package/dist/commands/remove.d.ts +3 -0
- package/dist/commands/remove.d.ts.map +1 -0
- package/dist/commands/remove.js +67 -0
- package/dist/commands/remove.js.map +1 -0
- package/dist/commands/update.d.ts +3 -0
- package/dist/commands/update.d.ts.map +1 -0
- package/dist/commands/update.js +58 -0
- package/dist/commands/update.js.map +1 -0
- package/dist/commands/validate.d.ts +3 -0
- package/dist/commands/validate.d.ts.map +1 -0
- package/dist/commands/validate.js +116 -0
- package/dist/commands/validate.js.map +1 -0
- package/dist/index.d.ts +3 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +48 -0
- package/dist/index.js.map +1 -0
- package/dist/lib/agents.d.ts +26 -0
- package/dist/lib/agents.d.ts.map +1 -0
- package/dist/lib/agents.js +87 -0
- package/dist/lib/agents.js.map +1 -0
- package/dist/lib/config.d.ts +9 -0
- package/dist/lib/config.d.ts.map +1 -0
- package/dist/lib/config.js +44 -0
- package/dist/lib/config.js.map +1 -0
- package/dist/lib/installer.d.ts +29 -0
- package/dist/lib/installer.d.ts.map +1 -0
- package/dist/lib/installer.js +124 -0
- package/dist/lib/installer.js.map +1 -0
- package/dist/lib/lock-file.d.ts +11 -0
- package/dist/lib/lock-file.d.ts.map +1 -0
- package/dist/lib/lock-file.js +72 -0
- package/dist/lib/lock-file.js.map +1 -0
- package/dist/lib/sources/github.d.ts +26 -0
- package/dist/lib/sources/github.d.ts.map +1 -0
- package/dist/lib/sources/github.js +182 -0
- package/dist/lib/sources/github.js.map +1 -0
- package/dist/lib/sources/local.d.ts +15 -0
- package/dist/lib/sources/local.d.ts.map +1 -0
- package/dist/lib/sources/local.js +52 -0
- package/dist/lib/sources/local.js.map +1 -0
- package/dist/lib/sources/registry.d.ts +21 -0
- package/dist/lib/sources/registry.d.ts.map +1 -0
- package/dist/lib/sources/registry.js +63 -0
- package/dist/lib/sources/registry.js.map +1 -0
- package/dist/lib/telemetry.d.ts +6 -0
- package/dist/lib/telemetry.d.ts.map +1 -0
- package/dist/lib/telemetry.js +68 -0
- package/dist/lib/telemetry.js.map +1 -0
- package/dist/lib/validator.d.ts +29 -0
- package/dist/lib/validator.d.ts.map +1 -0
- package/dist/lib/validator.js +107 -0
- package/dist/lib/validator.js.map +1 -0
- package/dist/types.d.ts +86 -0
- package/dist/types.d.ts.map +1 -0
- package/dist/types.js +2 -0
- package/dist/types.js.map +1 -0
- package/package.json +47 -0
|
@@ -0,0 +1,182 @@
|
|
|
1
|
+
import { mkdir, writeFile } from "node:fs/promises";
|
|
2
|
+
import { join, dirname } from "node:path";
|
|
3
|
+
const GITHUB_API = "https://api.github.com";
|
|
4
|
+
/**
|
|
5
|
+
* Parse a GitHub source string into a SquadSource object.
|
|
6
|
+
*
|
|
7
|
+
* Supported formats:
|
|
8
|
+
* owner/repo
|
|
9
|
+
* owner/repo/squad-name
|
|
10
|
+
* owner/repo#branch
|
|
11
|
+
* owner/repo/squad-name#branch
|
|
12
|
+
* https://github.com/owner/repo
|
|
13
|
+
* https://github.com/owner/repo/tree/branch/path
|
|
14
|
+
*/
|
|
15
|
+
export function parseGitHubSource(input) {
|
|
16
|
+
// Handle full GitHub URLs
|
|
17
|
+
const urlMatch = input.match(/^https?:\/\/github\.com\/([^/]+)\/([^/]+?)(?:\.git)?(?:\/tree\/([^/]+)(?:\/(.+))?)?$/);
|
|
18
|
+
if (urlMatch) {
|
|
19
|
+
return {
|
|
20
|
+
type: "github",
|
|
21
|
+
owner: urlMatch[1],
|
|
22
|
+
repo: urlMatch[2],
|
|
23
|
+
branch: urlMatch[3] || undefined,
|
|
24
|
+
squad: urlMatch[4] || undefined,
|
|
25
|
+
url: input,
|
|
26
|
+
};
|
|
27
|
+
}
|
|
28
|
+
// Handle owner/repo[/squad]#branch format
|
|
29
|
+
let branch;
|
|
30
|
+
let rest = input;
|
|
31
|
+
const hashIdx = input.indexOf("#");
|
|
32
|
+
if (hashIdx !== -1) {
|
|
33
|
+
branch = input.slice(hashIdx + 1);
|
|
34
|
+
rest = input.slice(0, hashIdx);
|
|
35
|
+
}
|
|
36
|
+
const parts = rest.split("/");
|
|
37
|
+
if (parts.length < 2) {
|
|
38
|
+
throw new Error(`Invalid GitHub source: "${input}". Expected format: owner/repo or owner/repo/squad-name`);
|
|
39
|
+
}
|
|
40
|
+
return {
|
|
41
|
+
type: "github",
|
|
42
|
+
owner: parts[0],
|
|
43
|
+
repo: parts[1],
|
|
44
|
+
squad: parts.length > 2 ? parts.slice(2).join("/") : undefined,
|
|
45
|
+
branch,
|
|
46
|
+
};
|
|
47
|
+
}
|
|
48
|
+
/**
|
|
49
|
+
* Fetch the repository tree from GitHub API.
|
|
50
|
+
*/
|
|
51
|
+
async function fetchRepoTree(owner, repo, branch) {
|
|
52
|
+
// Get default branch if not specified
|
|
53
|
+
if (!branch) {
|
|
54
|
+
const repoUrl = `${GITHUB_API}/repos/${owner}/${repo}`;
|
|
55
|
+
const repoRes = await fetch(repoUrl, {
|
|
56
|
+
headers: { Accept: "application/vnd.github.v3+json" },
|
|
57
|
+
});
|
|
58
|
+
if (!repoRes.ok) {
|
|
59
|
+
if (repoRes.status === 404) {
|
|
60
|
+
throw new Error(`Repository not found: ${owner}/${repo}`);
|
|
61
|
+
}
|
|
62
|
+
throw new Error(`GitHub API error: ${repoRes.status} ${repoRes.statusText}`);
|
|
63
|
+
}
|
|
64
|
+
const repoData = (await repoRes.json());
|
|
65
|
+
branch = repoData.default_branch;
|
|
66
|
+
}
|
|
67
|
+
const treeUrl = `${GITHUB_API}/repos/${owner}/${repo}/git/trees/${branch}?recursive=1`;
|
|
68
|
+
const treeRes = await fetch(treeUrl, {
|
|
69
|
+
headers: { Accept: "application/vnd.github.v3+json" },
|
|
70
|
+
});
|
|
71
|
+
if (!treeRes.ok) {
|
|
72
|
+
if (treeRes.status === 404) {
|
|
73
|
+
throw new Error(`Branch "${branch}" not found in ${owner}/${repo}`);
|
|
74
|
+
}
|
|
75
|
+
throw new Error(`GitHub API error: ${treeRes.status} ${treeRes.statusText}`);
|
|
76
|
+
}
|
|
77
|
+
const data = (await treeRes.json());
|
|
78
|
+
return { tree: data.tree, sha: data.sha };
|
|
79
|
+
}
|
|
80
|
+
/**
|
|
81
|
+
* Download a single file from GitHub.
|
|
82
|
+
*/
|
|
83
|
+
async function downloadFile(owner, repo, path, branch) {
|
|
84
|
+
const ref = branch ? `?ref=${branch}` : "";
|
|
85
|
+
const url = `${GITHUB_API}/repos/${owner}/${repo}/contents/${path}${ref}`;
|
|
86
|
+
const res = await fetch(url, {
|
|
87
|
+
headers: { Accept: "application/vnd.github.v3.raw" },
|
|
88
|
+
});
|
|
89
|
+
if (!res.ok) {
|
|
90
|
+
throw new Error(`Failed to download ${path}: ${res.status}`);
|
|
91
|
+
}
|
|
92
|
+
return res.text();
|
|
93
|
+
}
|
|
94
|
+
/**
|
|
95
|
+
* Find squad directories in a repository tree.
|
|
96
|
+
* A squad is identified by the presence of squad.yaml.
|
|
97
|
+
*/
|
|
98
|
+
export function findSquadsInTree(tree) {
|
|
99
|
+
const squadPaths = [];
|
|
100
|
+
for (const entry of tree) {
|
|
101
|
+
if (entry.type === "blob" && entry.path.endsWith("/squad.yaml")) {
|
|
102
|
+
squadPaths.push(dirname(entry.path));
|
|
103
|
+
}
|
|
104
|
+
// Also check root-level squad.yaml
|
|
105
|
+
if (entry.type === "blob" && entry.path === "squad.yaml") {
|
|
106
|
+
squadPaths.push(".");
|
|
107
|
+
}
|
|
108
|
+
}
|
|
109
|
+
return squadPaths;
|
|
110
|
+
}
|
|
111
|
+
/**
|
|
112
|
+
* Download a squad from GitHub to a local directory.
|
|
113
|
+
*/
|
|
114
|
+
export async function downloadSquad(source, targetDir) {
|
|
115
|
+
const { owner, repo, squad, branch } = source;
|
|
116
|
+
if (!owner || !repo) {
|
|
117
|
+
throw new Error("GitHub source requires owner and repo");
|
|
118
|
+
}
|
|
119
|
+
const { tree, sha } = await fetchRepoTree(owner, repo, branch);
|
|
120
|
+
// Determine which files belong to the squad
|
|
121
|
+
let squadPrefix = "";
|
|
122
|
+
if (squad) {
|
|
123
|
+
// User specified a specific squad path
|
|
124
|
+
squadPrefix = squad.endsWith("/") ? squad : `${squad}/`;
|
|
125
|
+
// Verify squad.yaml exists at that path
|
|
126
|
+
const hasManifest = tree.some((e) => e.type === "blob" &&
|
|
127
|
+
(e.path === `${squadPrefix}squad.yaml` ||
|
|
128
|
+
(squad === "." && e.path === "squad.yaml")));
|
|
129
|
+
if (!hasManifest) {
|
|
130
|
+
throw new Error(`No squad.yaml found at "${squad}" in ${owner}/${repo}`);
|
|
131
|
+
}
|
|
132
|
+
}
|
|
133
|
+
else {
|
|
134
|
+
// Auto-detect squad location
|
|
135
|
+
const squads = findSquadsInTree(tree);
|
|
136
|
+
if (squads.length === 0) {
|
|
137
|
+
throw new Error(`No squad found in ${owner}/${repo}. Make sure the repository contains a squad.yaml file.`);
|
|
138
|
+
}
|
|
139
|
+
if (squads.length === 1) {
|
|
140
|
+
squadPrefix = squads[0] === "." ? "" : `${squads[0]}/`;
|
|
141
|
+
}
|
|
142
|
+
else {
|
|
143
|
+
throw new Error(`Multiple squads found in ${owner}/${repo}: ${squads.join(", ")}. ` +
|
|
144
|
+
`Use --skill to specify which one to install.`);
|
|
145
|
+
}
|
|
146
|
+
}
|
|
147
|
+
// Filter tree entries to only those under the squad prefix
|
|
148
|
+
const squadFiles = tree.filter((e) => e.type === "blob" &&
|
|
149
|
+
(squadPrefix === ""
|
|
150
|
+
? true
|
|
151
|
+
: e.path.startsWith(squadPrefix)));
|
|
152
|
+
if (squadFiles.length === 0) {
|
|
153
|
+
throw new Error(`No files found for squad at "${squadPrefix}"`);
|
|
154
|
+
}
|
|
155
|
+
// Download each file
|
|
156
|
+
await mkdir(targetDir, { recursive: true });
|
|
157
|
+
for (const entry of squadFiles) {
|
|
158
|
+
const relativePath = squadPrefix
|
|
159
|
+
? entry.path.slice(squadPrefix.length)
|
|
160
|
+
: entry.path;
|
|
161
|
+
// Skip hidden files and directories not part of the squad
|
|
162
|
+
if (relativePath.startsWith(".") && !relativePath.startsWith(".claude")) {
|
|
163
|
+
continue;
|
|
164
|
+
}
|
|
165
|
+
const content = await downloadFile(owner, repo, entry.path, branch);
|
|
166
|
+
const destPath = join(targetDir, relativePath);
|
|
167
|
+
await mkdir(dirname(destPath), { recursive: true });
|
|
168
|
+
await writeFile(destPath, content, "utf-8");
|
|
169
|
+
}
|
|
170
|
+
return { sha };
|
|
171
|
+
}
|
|
172
|
+
export function formatGitHubSource(source) {
|
|
173
|
+
let result = `${source.owner}/${source.repo}`;
|
|
174
|
+
if (source.squad) {
|
|
175
|
+
result += `/${source.squad}`;
|
|
176
|
+
}
|
|
177
|
+
if (source.branch) {
|
|
178
|
+
result += `#${source.branch}`;
|
|
179
|
+
}
|
|
180
|
+
return result;
|
|
181
|
+
}
|
|
182
|
+
//# sourceMappingURL=github.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"github.js","sourceRoot":"","sources":["../../../src/lib/sources/github.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
import type { SquadSource } from "../../types.js";
|
|
2
|
+
/**
|
|
3
|
+
* Parse a local path source.
|
|
4
|
+
*/
|
|
5
|
+
export declare function parseLocalSource(input: string): SquadSource;
|
|
6
|
+
/**
|
|
7
|
+
* Check if a source string looks like a local path.
|
|
8
|
+
*/
|
|
9
|
+
export declare function isLocalPath(input: string): boolean;
|
|
10
|
+
/**
|
|
11
|
+
* Copy a squad from a local path to the target directory.
|
|
12
|
+
* Validates the source directory before copying.
|
|
13
|
+
*/
|
|
14
|
+
export declare function copyLocalSquad(source: SquadSource, targetDir: string): Promise<void>;
|
|
15
|
+
//# sourceMappingURL=local.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"local.d.ts","sourceRoot":"","sources":["../../../src/lib/sources/local.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,gBAAgB,CAAC;AAGlD;;GAEG;AACH,wBAAgB,gBAAgB,CAAC,KAAK,EAAE,MAAM,GAAG,WAAW,CAK3D;AAED;;GAEG;AACH,wBAAgB,WAAW,CAAC,KAAK,EAAE,MAAM,GAAG,OAAO,CAOlD;AAED;;;GAGG;AACH,wBAAsB,cAAc,CAClC,MAAM,EAAE,WAAW,EACnB,SAAS,EAAE,MAAM,GAChB,OAAO,CAAC,IAAI,CAAC,CA6Bf"}
|
|
@@ -0,0 +1,52 @@
|
|
|
1
|
+
import { cp, stat } from "node:fs/promises";
|
|
2
|
+
import { resolve } from "node:path";
|
|
3
|
+
import { validateSquadDirectory } from "../validator.js";
|
|
4
|
+
/**
|
|
5
|
+
* Parse a local path source.
|
|
6
|
+
*/
|
|
7
|
+
export function parseLocalSource(input) {
|
|
8
|
+
return {
|
|
9
|
+
type: "local",
|
|
10
|
+
path: resolve(input),
|
|
11
|
+
};
|
|
12
|
+
}
|
|
13
|
+
/**
|
|
14
|
+
* Check if a source string looks like a local path.
|
|
15
|
+
*/
|
|
16
|
+
export function isLocalPath(input) {
|
|
17
|
+
return (input.startsWith("/") ||
|
|
18
|
+
input.startsWith("./") ||
|
|
19
|
+
input.startsWith("../") ||
|
|
20
|
+
input.startsWith("~"));
|
|
21
|
+
}
|
|
22
|
+
/**
|
|
23
|
+
* Copy a squad from a local path to the target directory.
|
|
24
|
+
* Validates the source directory before copying.
|
|
25
|
+
*/
|
|
26
|
+
export async function copyLocalSquad(source, targetDir) {
|
|
27
|
+
const sourcePath = source.path;
|
|
28
|
+
if (!sourcePath) {
|
|
29
|
+
throw new Error("Local source requires a path");
|
|
30
|
+
}
|
|
31
|
+
// Verify source exists and is a directory
|
|
32
|
+
try {
|
|
33
|
+
const pathStat = await stat(sourcePath);
|
|
34
|
+
if (!pathStat.isDirectory()) {
|
|
35
|
+
throw new Error(`Source path is not a directory: ${sourcePath}`);
|
|
36
|
+
}
|
|
37
|
+
}
|
|
38
|
+
catch (err) {
|
|
39
|
+
if (err.code === "ENOENT") {
|
|
40
|
+
throw new Error(`Source path does not exist: ${sourcePath}`);
|
|
41
|
+
}
|
|
42
|
+
throw err;
|
|
43
|
+
}
|
|
44
|
+
// Validate source squad
|
|
45
|
+
const validation = await validateSquadDirectory(sourcePath);
|
|
46
|
+
if (!validation.valid) {
|
|
47
|
+
throw new Error(`Invalid squad at ${sourcePath}:\n - ${validation.errors.join("\n - ")}`);
|
|
48
|
+
}
|
|
49
|
+
// Copy files
|
|
50
|
+
await cp(sourcePath, targetDir, { recursive: true });
|
|
51
|
+
}
|
|
52
|
+
//# sourceMappingURL=local.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"local.js","sourceRoot":"","sources":["../../../src/lib/sources/local.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,EAAE,EAAE,IAAI,EAAE,MAAM,kBAAkB,CAAC;AAC5C,OAAO,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AAEpC,OAAO,EAAE,sBAAsB,EAAE,MAAM,iBAAiB,CAAC;AAEzD;;GAEG;AACH,MAAM,UAAU,gBAAgB,CAAC,KAAa;IAC5C,OAAO;QACL,IAAI,EAAE,OAAO;QACb,IAAI,EAAE,OAAO,CAAC,KAAK,CAAC;KACrB,CAAC;AACJ,CAAC;AAED;;GAEG;AACH,MAAM,UAAU,WAAW,CAAC,KAAa;IACvC,OAAO,CACL,KAAK,CAAC,UAAU,CAAC,GAAG,CAAC;QACrB,KAAK,CAAC,UAAU,CAAC,IAAI,CAAC;QACtB,KAAK,CAAC,UAAU,CAAC,KAAK,CAAC;QACvB,KAAK,CAAC,UAAU,CAAC,GAAG,CAAC,CACtB,CAAC;AACJ,CAAC;AAED;;;GAGG;AACH,MAAM,CAAC,KAAK,UAAU,cAAc,CAClC,MAAmB,EACnB,SAAiB;IAEjB,MAAM,UAAU,GAAG,MAAM,CAAC,IAAI,CAAC;IAC/B,IAAI,CAAC,UAAU,EAAE,CAAC;QAChB,MAAM,IAAI,KAAK,CAAC,8BAA8B,CAAC,CAAC;IAClD,CAAC;IAED,0CAA0C;IAC1C,IAAI,CAAC;QACH,MAAM,QAAQ,GAAG,MAAM,IAAI,CAAC,UAAU,CAAC,CAAC;QACxC,IAAI,CAAC,QAAQ,CAAC,WAAW,EAAE,EAAE,CAAC;YAC5B,MAAM,IAAI,KAAK,CAAC,mCAAmC,UAAU,EAAE,CAAC,CAAC;QACnE,CAAC;IACH,CAAC;IAAC,OAAO,GAAG,EAAE,CAAC;QACb,IAAK,GAA6B,CAAC,IAAI,KAAK,QAAQ,EAAE,CAAC;YACrD,MAAM,IAAI,KAAK,CAAC,+BAA+B,UAAU,EAAE,CAAC,CAAC;QAC/D,CAAC;QACD,MAAM,GAAG,CAAC;IACZ,CAAC;IAED,wBAAwB;IACxB,MAAM,UAAU,GAAG,MAAM,sBAAsB,CAAC,UAAU,CAAC,CAAC;IAC5D,IAAI,CAAC,UAAU,CAAC,KAAK,EAAE,CAAC;QACtB,MAAM,IAAI,KAAK,CACb,oBAAoB,UAAU,UAAU,UAAU,CAAC,MAAM,CAAC,IAAI,CAAC,QAAQ,CAAC,EAAE,CAC3E,CAAC;IACJ,CAAC;IAED,aAAa;IACb,MAAM,EAAE,CAAC,UAAU,EAAE,SAAS,EAAE,EAAE,SAAS,EAAE,IAAI,EAAE,CAAC,CAAC;AACvD,CAAC"}
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
import type { SquadSource, SearchResult } from "../../types.js";
|
|
2
|
+
/**
|
|
3
|
+
* Check if a source string looks like a registry slug (simple name, no slashes or dots).
|
|
4
|
+
*/
|
|
5
|
+
export declare function isRegistrySlug(input: string): boolean;
|
|
6
|
+
/**
|
|
7
|
+
* Resolve a registry slug to a SquadSource by fetching metadata from squads.sh API.
|
|
8
|
+
*/
|
|
9
|
+
export declare function resolveRegistrySource(slug: string): Promise<SquadSource>;
|
|
10
|
+
/**
|
|
11
|
+
* Download a squad from the registry (resolves to GitHub source, then downloads).
|
|
12
|
+
*/
|
|
13
|
+
export declare function downloadRegistrySquad(slug: string, targetDir: string): Promise<{
|
|
14
|
+
sha: string;
|
|
15
|
+
source: SquadSource;
|
|
16
|
+
}>;
|
|
17
|
+
/**
|
|
18
|
+
* Search the registry for squads matching a query.
|
|
19
|
+
*/
|
|
20
|
+
export declare function searchRegistry(query: string, limit?: number): Promise<SearchResult[]>;
|
|
21
|
+
//# sourceMappingURL=registry.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"registry.d.ts","sourceRoot":"","sources":["../../../src/lib/sources/registry.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,WAAW,EAAE,YAAY,EAAE,MAAM,gBAAgB,CAAC;AAGhE;;GAEG;AACH,wBAAgB,cAAc,CAAC,KAAK,EAAE,MAAM,GAAG,OAAO,CAErD;AAED;;GAEG;AACH,wBAAsB,qBAAqB,CACzC,IAAI,EAAE,MAAM,GACX,OAAO,CAAC,WAAW,CAAC,CA+BtB;AAED;;GAEG;AACH,wBAAsB,qBAAqB,CACzC,IAAI,EAAE,MAAM,EACZ,SAAS,EAAE,MAAM,GAChB,OAAO,CAAC;IAAE,GAAG,EAAE,MAAM,CAAC;IAAC,MAAM,EAAE,WAAW,CAAA;CAAE,CAAC,CAI/C;AAED;;GAEG;AACH,wBAAsB,cAAc,CAClC,KAAK,EAAE,MAAM,EACb,KAAK,GAAE,MAAW,GACjB,OAAO,CAAC,YAAY,EAAE,CAAC,CAyBzB"}
|
|
@@ -0,0 +1,63 @@
|
|
|
1
|
+
import { getRegistryUrl } from "../config.js";
|
|
2
|
+
import { parseGitHubSource, downloadSquad } from "./github.js";
|
|
3
|
+
/**
|
|
4
|
+
* Check if a source string looks like a registry slug (simple name, no slashes or dots).
|
|
5
|
+
*/
|
|
6
|
+
export function isRegistrySlug(input) {
|
|
7
|
+
return /^[a-z0-9]([a-z0-9-]*[a-z0-9])?$/.test(input);
|
|
8
|
+
}
|
|
9
|
+
/**
|
|
10
|
+
* Resolve a registry slug to a SquadSource by fetching metadata from squads.sh API.
|
|
11
|
+
*/
|
|
12
|
+
export async function resolveRegistrySource(slug) {
|
|
13
|
+
const registryUrl = await getRegistryUrl();
|
|
14
|
+
const url = `${registryUrl}/api/squads?slug=${encodeURIComponent(slug)}`;
|
|
15
|
+
const res = await fetch(url, {
|
|
16
|
+
headers: { Accept: "application/json" },
|
|
17
|
+
});
|
|
18
|
+
if (!res.ok) {
|
|
19
|
+
if (res.status === 404) {
|
|
20
|
+
throw new Error(`Squad "${slug}" not found on squads.sh. Run "squads find ${slug}" to search.`);
|
|
21
|
+
}
|
|
22
|
+
throw new Error(`Registry API error: ${res.status} ${res.statusText}`);
|
|
23
|
+
}
|
|
24
|
+
const data = (await res.json());
|
|
25
|
+
if (!data.repo_url) {
|
|
26
|
+
throw new Error(`Squad "${slug}" has no repository URL configured.`);
|
|
27
|
+
}
|
|
28
|
+
// Parse the repo URL into a GitHub source
|
|
29
|
+
const source = parseGitHubSource(data.repo_url);
|
|
30
|
+
source.type = "registry";
|
|
31
|
+
return source;
|
|
32
|
+
}
|
|
33
|
+
/**
|
|
34
|
+
* Download a squad from the registry (resolves to GitHub source, then downloads).
|
|
35
|
+
*/
|
|
36
|
+
export async function downloadRegistrySquad(slug, targetDir) {
|
|
37
|
+
const source = await resolveRegistrySource(slug);
|
|
38
|
+
const { sha } = await downloadSquad(source, targetDir);
|
|
39
|
+
return { sha, source };
|
|
40
|
+
}
|
|
41
|
+
/**
|
|
42
|
+
* Search the registry for squads matching a query.
|
|
43
|
+
*/
|
|
44
|
+
export async function searchRegistry(query, limit = 20) {
|
|
45
|
+
const registryUrl = await getRegistryUrl();
|
|
46
|
+
const url = `${registryUrl}/api/search?q=${encodeURIComponent(query)}&limit=${limit}`;
|
|
47
|
+
const res = await fetch(url, {
|
|
48
|
+
headers: { Accept: "application/json" },
|
|
49
|
+
});
|
|
50
|
+
if (!res.ok) {
|
|
51
|
+
throw new Error(`Registry search failed: ${res.status} ${res.statusText}`);
|
|
52
|
+
}
|
|
53
|
+
const data = (await res.json());
|
|
54
|
+
// Handle both array and wrapped response formats
|
|
55
|
+
if (Array.isArray(data)) {
|
|
56
|
+
return data;
|
|
57
|
+
}
|
|
58
|
+
if (data && "results" in data) {
|
|
59
|
+
return data.results;
|
|
60
|
+
}
|
|
61
|
+
return [];
|
|
62
|
+
}
|
|
63
|
+
//# sourceMappingURL=registry.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"registry.js","sourceRoot":"","sources":["../../../src/lib/sources/registry.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,cAAc,EAAE,MAAM,cAAc,CAAC;AAE9C,OAAO,EAAE,iBAAiB,EAAE,aAAa,EAAE,MAAM,aAAa,CAAC;AAE/D;;GAEG;AACH,MAAM,UAAU,cAAc,CAAC,KAAa;IAC1C,OAAO,iCAAiC,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC;AACvD,CAAC;AAED;;GAEG;AACH,MAAM,CAAC,KAAK,UAAU,qBAAqB,CACzC,IAAY;IAEZ,MAAM,WAAW,GAAG,MAAM,cAAc,EAAE,CAAC;IAC3C,MAAM,GAAG,GAAG,GAAG,WAAW,oBAAoB,kBAAkB,CAAC,IAAI,CAAC,EAAE,CAAC;IAEzE,MAAM,GAAG,GAAG,MAAM,KAAK,CAAC,GAAG,EAAE;QAC3B,OAAO,EAAE,EAAE,MAAM,EAAE,kBAAkB,EAAE;KACxC,CAAC,CAAC;IAEH,IAAI,CAAC,GAAG,CAAC,EAAE,EAAE,CAAC;QACZ,IAAI,GAAG,CAAC,MAAM,KAAK,GAAG,EAAE,CAAC;YACvB,MAAM,IAAI,KAAK,CACb,UAAU,IAAI,8CAA8C,IAAI,cAAc,CAC/E,CAAC;QACJ,CAAC;QACD,MAAM,IAAI,KAAK,CACb,uBAAuB,GAAG,CAAC,MAAM,IAAI,GAAG,CAAC,UAAU,EAAE,CACtD,CAAC;IACJ,CAAC;IAED,MAAM,IAAI,GAAG,CAAC,MAAM,GAAG,CAAC,IAAI,EAAE,CAAiB,CAAC;IAEhD,IAAI,CAAC,IAAI,CAAC,QAAQ,EAAE,CAAC;QACnB,MAAM,IAAI,KAAK,CACb,UAAU,IAAI,qCAAqC,CACpD,CAAC;IACJ,CAAC;IAED,0CAA0C;IAC1C,MAAM,MAAM,GAAG,iBAAiB,CAAC,IAAI,CAAC,QAAQ,CAAC,CAAC;IAChD,MAAM,CAAC,IAAI,GAAG,UAAU,CAAC;IACzB,OAAO,MAAM,CAAC;AAChB,CAAC;AAED;;GAEG;AACH,MAAM,CAAC,KAAK,UAAU,qBAAqB,CACzC,IAAY,EACZ,SAAiB;IAEjB,MAAM,MAAM,GAAG,MAAM,qBAAqB,CAAC,IAAI,CAAC,CAAC;IACjD,MAAM,EAAE,GAAG,EAAE,GAAG,MAAM,aAAa,CAAC,MAAM,EAAE,SAAS,CAAC,CAAC;IACvD,OAAO,EAAE,GAAG,EAAE,MAAM,EAAE,CAAC;AACzB,CAAC;AAED;;GAEG;AACH,MAAM,CAAC,KAAK,UAAU,cAAc,CAClC,KAAa,EACb,QAAgB,EAAE;IAElB,MAAM,WAAW,GAAG,MAAM,cAAc,EAAE,CAAC;IAC3C,MAAM,GAAG,GAAG,GAAG,WAAW,iBAAiB,kBAAkB,CAAC,KAAK,CAAC,UAAU,KAAK,EAAE,CAAC;IAEtF,MAAM,GAAG,GAAG,MAAM,KAAK,CAAC,GAAG,EAAE;QAC3B,OAAO,EAAE,EAAE,MAAM,EAAE,kBAAkB,EAAE;KACxC,CAAC,CAAC;IAEH,IAAI,CAAC,GAAG,CAAC,EAAE,EAAE,CAAC;QACZ,MAAM,IAAI,KAAK,CACb,2BAA2B,GAAG,CAAC,MAAM,IAAI,GAAG,CAAC,UAAU,EAAE,CAC1D,CAAC;IACJ,CAAC;IAED,MAAM,IAAI,GAAG,CAAC,MAAM,GAAG,CAAC,IAAI,EAAE,CAAiD,CAAC;IAEhF,iDAAiD;IACjD,IAAI,KAAK,CAAC,OAAO,CAAC,IAAI,CAAC,EAAE,CAAC;QACxB,OAAO,IAAI,CAAC;IACd,CAAC;IACD,IAAI,IAAI,IAAI,SAAS,IAAI,IAAI,EAAE,CAAC;QAC9B,OAAO,IAAI,CAAC,OAAO,CAAC;IACtB,CAAC;IAED,OAAO,EAAE,CAAC;AACZ,CAAC"}
|
|
@@ -0,0 +1,6 @@
|
|
|
1
|
+
import type { TelemetryEvent } from "../types.js";
|
|
2
|
+
export declare function trackEvent(event: TelemetryEvent): Promise<void>;
|
|
3
|
+
export declare function trackInstall(squadSlug: string, sourceType: string, isGlobal: boolean): void;
|
|
4
|
+
export declare function trackRemove(squadSlug: string, sourceType: string): void;
|
|
5
|
+
export declare function trackFind(query: string): void;
|
|
6
|
+
//# sourceMappingURL=telemetry.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"telemetry.d.ts","sourceRoot":"","sources":["../../src/lib/telemetry.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,aAAa,CAAC;AAgBlD,wBAAsB,UAAU,CAAC,KAAK,EAAE,cAAc,GAAG,OAAO,CAAC,IAAI,CAAC,CA4BrE;AAED,wBAAgB,YAAY,CAC1B,SAAS,EAAE,MAAM,EACjB,UAAU,EAAE,MAAM,EAClB,QAAQ,EAAE,OAAO,GAChB,IAAI,CAQN;AAED,wBAAgB,WAAW,CAAC,SAAS,EAAE,MAAM,EAAE,UAAU,EAAE,MAAM,GAAG,IAAI,CAQvE;AAED,wBAAgB,SAAS,CAAC,KAAK,EAAE,MAAM,GAAG,IAAI,CAQ7C"}
|
|
@@ -0,0 +1,68 @@
|
|
|
1
|
+
import { readConfig } from "./config.js";
|
|
2
|
+
function isCI() {
|
|
3
|
+
return !!(process.env["CI"] ||
|
|
4
|
+
process.env["GITHUB_ACTIONS"] ||
|
|
5
|
+
process.env["GITLAB_CI"] ||
|
|
6
|
+
process.env["CIRCLECI"] ||
|
|
7
|
+
process.env["TRAVIS"] ||
|
|
8
|
+
process.env["JENKINS_URL"] ||
|
|
9
|
+
process.env["BUILDKITE"] ||
|
|
10
|
+
process.env["TF_BUILD"] ||
|
|
11
|
+
process.env["CODEBUILD_BUILD_ID"]);
|
|
12
|
+
}
|
|
13
|
+
export async function trackEvent(event) {
|
|
14
|
+
try {
|
|
15
|
+
const config = await readConfig();
|
|
16
|
+
if (config.telemetryOptOut)
|
|
17
|
+
return;
|
|
18
|
+
const url = `${config.registry}/api/telemetry`;
|
|
19
|
+
const payload = {
|
|
20
|
+
...event,
|
|
21
|
+
is_ci: isCI(),
|
|
22
|
+
cli_version: "0.1.0",
|
|
23
|
+
node_version: process.version,
|
|
24
|
+
platform: process.platform,
|
|
25
|
+
timestamp: new Date().toISOString(),
|
|
26
|
+
};
|
|
27
|
+
// Fire-and-forget: do not await, do not throw
|
|
28
|
+
fetch(url, {
|
|
29
|
+
method: "POST",
|
|
30
|
+
headers: { "Content-Type": "application/json" },
|
|
31
|
+
body: JSON.stringify(payload),
|
|
32
|
+
signal: AbortSignal.timeout(5000),
|
|
33
|
+
}).catch(() => {
|
|
34
|
+
// Silently ignore telemetry failures
|
|
35
|
+
});
|
|
36
|
+
}
|
|
37
|
+
catch {
|
|
38
|
+
// Silently ignore all telemetry errors
|
|
39
|
+
}
|
|
40
|
+
}
|
|
41
|
+
export function trackInstall(squadSlug, sourceType, isGlobal) {
|
|
42
|
+
void trackEvent({
|
|
43
|
+
event: "install",
|
|
44
|
+
squad_slug: squadSlug,
|
|
45
|
+
source_type: sourceType,
|
|
46
|
+
is_global: isGlobal,
|
|
47
|
+
is_ci: isCI(),
|
|
48
|
+
});
|
|
49
|
+
}
|
|
50
|
+
export function trackRemove(squadSlug, sourceType) {
|
|
51
|
+
void trackEvent({
|
|
52
|
+
event: "remove",
|
|
53
|
+
squad_slug: squadSlug,
|
|
54
|
+
source_type: sourceType,
|
|
55
|
+
is_global: false,
|
|
56
|
+
is_ci: isCI(),
|
|
57
|
+
});
|
|
58
|
+
}
|
|
59
|
+
export function trackFind(query) {
|
|
60
|
+
void trackEvent({
|
|
61
|
+
event: "find",
|
|
62
|
+
squad_slug: query,
|
|
63
|
+
source_type: "registry",
|
|
64
|
+
is_global: false,
|
|
65
|
+
is_ci: isCI(),
|
|
66
|
+
});
|
|
67
|
+
}
|
|
68
|
+
//# sourceMappingURL=telemetry.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"telemetry.js","sourceRoot":"","sources":["../../src/lib/telemetry.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,UAAU,EAAE,MAAM,aAAa,CAAC;AAGzC,SAAS,IAAI;IACX,OAAO,CAAC,CAAC,CACP,OAAO,CAAC,GAAG,CAAC,IAAI,CAAC;QACjB,OAAO,CAAC,GAAG,CAAC,gBAAgB,CAAC;QAC7B,OAAO,CAAC,GAAG,CAAC,WAAW,CAAC;QACxB,OAAO,CAAC,GAAG,CAAC,UAAU,CAAC;QACvB,OAAO,CAAC,GAAG,CAAC,QAAQ,CAAC;QACrB,OAAO,CAAC,GAAG,CAAC,aAAa,CAAC;QAC1B,OAAO,CAAC,GAAG,CAAC,WAAW,CAAC;QACxB,OAAO,CAAC,GAAG,CAAC,UAAU,CAAC;QACvB,OAAO,CAAC,GAAG,CAAC,oBAAoB,CAAC,CAClC,CAAC;AACJ,CAAC;AAED,MAAM,CAAC,KAAK,UAAU,UAAU,CAAC,KAAqB;IACpD,IAAI,CAAC;QACH,MAAM,MAAM,GAAG,MAAM,UAAU,EAAE,CAAC;QAClC,IAAI,MAAM,CAAC,eAAe;YAAE,OAAO;QAEnC,MAAM,GAAG,GAAG,GAAG,MAAM,CAAC,QAAQ,gBAAgB,CAAC;QAE/C,MAAM,OAAO,GAAG;YACd,GAAG,KAAK;YACR,KAAK,EAAE,IAAI,EAAE;YACb,WAAW,EAAE,OAAO;YACpB,YAAY,EAAE,OAAO,CAAC,OAAO;YAC7B,QAAQ,EAAE,OAAO,CAAC,QAAQ;YAC1B,SAAS,EAAE,IAAI,IAAI,EAAE,CAAC,WAAW,EAAE;SACpC,CAAC;QAEF,8CAA8C;QAC9C,KAAK,CAAC,GAAG,EAAE;YACT,MAAM,EAAE,MAAM;YACd,OAAO,EAAE,EAAE,cAAc,EAAE,kBAAkB,EAAE;YAC/C,IAAI,EAAE,IAAI,CAAC,SAAS,CAAC,OAAO,CAAC;YAC7B,MAAM,EAAE,WAAW,CAAC,OAAO,CAAC,IAAI,CAAC;SAClC,CAAC,CAAC,KAAK,CAAC,GAAG,EAAE;YACZ,qCAAqC;QACvC,CAAC,CAAC,CAAC;IACL,CAAC;IAAC,MAAM,CAAC;QACP,uCAAuC;IACzC,CAAC;AACH,CAAC;AAED,MAAM,UAAU,YAAY,CAC1B,SAAiB,EACjB,UAAkB,EAClB,QAAiB;IAEjB,KAAK,UAAU,CAAC;QACd,KAAK,EAAE,SAAS;QAChB,UAAU,EAAE,SAAS;QACrB,WAAW,EAAE,UAAU;QACvB,SAAS,EAAE,QAAQ;QACnB,KAAK,EAAE,IAAI,EAAE;KACd,CAAC,CAAC;AACL,CAAC;AAED,MAAM,UAAU,WAAW,CAAC,SAAiB,EAAE,UAAkB;IAC/D,KAAK,UAAU,CAAC;QACd,KAAK,EAAE,QAAQ;QACf,UAAU,EAAE,SAAS;QACrB,WAAW,EAAE,UAAU;QACvB,SAAS,EAAE,KAAK;QAChB,KAAK,EAAE,IAAI,EAAE;KACd,CAAC,CAAC;AACL,CAAC;AAED,MAAM,UAAU,SAAS,CAAC,KAAa;IACrC,KAAK,UAAU,CAAC;QACd,KAAK,EAAE,MAAM;QACb,UAAU,EAAE,KAAK;QACjB,WAAW,EAAE,UAAU;QACvB,SAAS,EAAE,KAAK;QAChB,KAAK,EAAE,IAAI,EAAE;KACd,CAAC,CAAC;AACL,CAAC"}
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
import type { ValidationReport } from "@squads-sh/validator";
|
|
2
|
+
import type { SquadManifest } from "../types.js";
|
|
3
|
+
/** Re-export the deep validation report type */
|
|
4
|
+
export type { ValidationReport as DeepValidationReport };
|
|
5
|
+
/**
|
|
6
|
+
* Backward-compatible validation result.
|
|
7
|
+
* Kept for existing consumers (e.g. publish command).
|
|
8
|
+
*/
|
|
9
|
+
export interface ValidationResult {
|
|
10
|
+
valid: boolean;
|
|
11
|
+
errors: string[];
|
|
12
|
+
warnings: string[];
|
|
13
|
+
manifest?: SquadManifest;
|
|
14
|
+
}
|
|
15
|
+
/**
|
|
16
|
+
* Validate a squad directory using the deep validator,
|
|
17
|
+
* then map the result back to the legacy ValidationResult format.
|
|
18
|
+
*/
|
|
19
|
+
export declare function validateSquadDirectory(dirPath: string): Promise<ValidationResult>;
|
|
20
|
+
/**
|
|
21
|
+
* Deep validation — returns the full ValidationReport with scores,
|
|
22
|
+
* categories, and per-finding details.
|
|
23
|
+
*/
|
|
24
|
+
export declare function validateSquadDeep(dirPath: string): Promise<ValidationReport>;
|
|
25
|
+
/**
|
|
26
|
+
* List agent .md files in the squad's agents/ directory.
|
|
27
|
+
*/
|
|
28
|
+
export declare function listAgentFiles(dirPath: string): Promise<string[]>;
|
|
29
|
+
//# sourceMappingURL=validator.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"validator.d.ts","sourceRoot":"","sources":["../../src/lib/validator.ts"],"names":[],"mappings":"AAIA,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,sBAAsB,CAAC;AAC7D,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,aAAa,CAAC;AAEjD,gDAAgD;AAChD,YAAY,EAAE,gBAAgB,IAAI,oBAAoB,EAAE,CAAC;AAEzD;;;GAGG;AACH,MAAM,WAAW,gBAAgB;IAC/B,KAAK,EAAE,OAAO,CAAC;IACf,MAAM,EAAE,MAAM,EAAE,CAAC;IACjB,QAAQ,EAAE,MAAM,EAAE,CAAC;IACnB,QAAQ,CAAC,EAAE,aAAa,CAAC;CAC1B;AAED;;;GAGG;AACH,wBAAsB,sBAAsB,CAC1C,OAAO,EAAE,MAAM,GACd,OAAO,CAAC,gBAAgB,CAAC,CA2B3B;AAED;;;GAGG;AACH,wBAAsB,iBAAiB,CACrC,OAAO,EAAE,MAAM,GACd,OAAO,CAAC,gBAAgB,CAAC,CAG3B;AAED;;GAEG;AACH,wBAAsB,cAAc,CAAC,OAAO,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,EAAE,CAAC,CAQvE"}
|
|
@@ -0,0 +1,107 @@
|
|
|
1
|
+
import { readdir } from "node:fs/promises";
|
|
2
|
+
import { join } from "node:path";
|
|
3
|
+
import { validateSquad } from "@squads-sh/validator";
|
|
4
|
+
import { buildFileTreeFromFS } from "@squads-sh/validator/adapters/filesystem";
|
|
5
|
+
/**
|
|
6
|
+
* Validate a squad directory using the deep validator,
|
|
7
|
+
* then map the result back to the legacy ValidationResult format.
|
|
8
|
+
*/
|
|
9
|
+
export async function validateSquadDirectory(dirPath) {
|
|
10
|
+
const report = await validateSquadDeep(dirPath);
|
|
11
|
+
const errors = report.findings
|
|
12
|
+
.filter((f) => f.severity === "error")
|
|
13
|
+
.map((f) => (f.file ? `[${f.file}] ${f.message}` : f.message));
|
|
14
|
+
const warnings = report.findings
|
|
15
|
+
.filter((f) => f.severity === "warning")
|
|
16
|
+
.map((f) => (f.file ? `[${f.file}] ${f.message}` : f.message));
|
|
17
|
+
// Try to extract a manifest from the file tree for backward compat
|
|
18
|
+
let manifest;
|
|
19
|
+
if (report.summary.totalErrors === 0) {
|
|
20
|
+
const fileTree = await buildFileTreeFromFS(dirPath);
|
|
21
|
+
const yamlContent = fileTree.get("squad.yaml");
|
|
22
|
+
if (yamlContent) {
|
|
23
|
+
manifest = parseManifestFromYaml(yamlContent);
|
|
24
|
+
}
|
|
25
|
+
}
|
|
26
|
+
return {
|
|
27
|
+
valid: report.summary.totalErrors === 0,
|
|
28
|
+
errors,
|
|
29
|
+
warnings,
|
|
30
|
+
manifest,
|
|
31
|
+
};
|
|
32
|
+
}
|
|
33
|
+
/**
|
|
34
|
+
* Deep validation — returns the full ValidationReport with scores,
|
|
35
|
+
* categories, and per-finding details.
|
|
36
|
+
*/
|
|
37
|
+
export async function validateSquadDeep(dirPath) {
|
|
38
|
+
const fileTree = await buildFileTreeFromFS(dirPath);
|
|
39
|
+
return validateSquad(fileTree);
|
|
40
|
+
}
|
|
41
|
+
/**
|
|
42
|
+
* List agent .md files in the squad's agents/ directory.
|
|
43
|
+
*/
|
|
44
|
+
export async function listAgentFiles(dirPath) {
|
|
45
|
+
const agentsDir = join(dirPath, "agents");
|
|
46
|
+
try {
|
|
47
|
+
const files = await readdir(agentsDir);
|
|
48
|
+
return files.filter((f) => f.endsWith(".md"));
|
|
49
|
+
}
|
|
50
|
+
catch {
|
|
51
|
+
return [];
|
|
52
|
+
}
|
|
53
|
+
}
|
|
54
|
+
/**
|
|
55
|
+
* Lightweight YAML key-value extraction for building SquadManifest.
|
|
56
|
+
* Not a full YAML parser — only extracts top-level and one-level-nested scalars.
|
|
57
|
+
*/
|
|
58
|
+
function parseManifestFromYaml(content) {
|
|
59
|
+
const result = {};
|
|
60
|
+
const lines = content.split("\n");
|
|
61
|
+
const stack = [
|
|
62
|
+
{ indent: -1, obj: result },
|
|
63
|
+
];
|
|
64
|
+
for (const line of lines) {
|
|
65
|
+
const trimmed = line.trimEnd();
|
|
66
|
+
if (!trimmed || trimmed.startsWith("#"))
|
|
67
|
+
continue;
|
|
68
|
+
const indent = line.length - line.trimStart().length;
|
|
69
|
+
const match = trimmed.match(/^(\s*)([^:]+):\s*(.*)$/);
|
|
70
|
+
if (!match)
|
|
71
|
+
continue;
|
|
72
|
+
const key = match[2].trim();
|
|
73
|
+
const value = match[3].trim();
|
|
74
|
+
while (stack.length > 1 && stack[stack.length - 1].indent >= indent) {
|
|
75
|
+
stack.pop();
|
|
76
|
+
}
|
|
77
|
+
const parent = stack[stack.length - 1].obj;
|
|
78
|
+
if (value === "" || value === "|" || value === ">") {
|
|
79
|
+
const nested = {};
|
|
80
|
+
parent[key] = nested;
|
|
81
|
+
stack.push({ indent, obj: nested });
|
|
82
|
+
}
|
|
83
|
+
else {
|
|
84
|
+
const stripped = value.replace(/^["'](.*)["']$/, "$1");
|
|
85
|
+
parent[key] = stripped;
|
|
86
|
+
}
|
|
87
|
+
}
|
|
88
|
+
const name = result["name"];
|
|
89
|
+
const version = result["version"];
|
|
90
|
+
const description = result["description"];
|
|
91
|
+
const aios = result["aios"];
|
|
92
|
+
if (!name || !version || !description || !aios?.["minVersion"] || !aios?.["type"]) {
|
|
93
|
+
return undefined;
|
|
94
|
+
}
|
|
95
|
+
return {
|
|
96
|
+
name,
|
|
97
|
+
version,
|
|
98
|
+
description,
|
|
99
|
+
slashPrefix: result["slashPrefix"],
|
|
100
|
+
aios: {
|
|
101
|
+
minVersion: aios["minVersion"],
|
|
102
|
+
type: aios["type"],
|
|
103
|
+
},
|
|
104
|
+
components: result["components"],
|
|
105
|
+
};
|
|
106
|
+
}
|
|
107
|
+
//# sourceMappingURL=validator.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"validator.js","sourceRoot":"","sources":["../../src/lib/validator.ts"],"names":[],"mappings":"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"}
|