@halyard/cli 0.1.1 → 0.2.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/README.md +115 -0
- package/dist/cli.js +30 -3
- package/dist/cli.js.map +1 -1
- package/dist/commands/api-keys.d.ts +3 -0
- package/dist/commands/api-keys.d.ts.map +1 -0
- package/dist/commands/api-keys.js +90 -0
- package/dist/commands/api-keys.js.map +1 -0
- package/dist/commands/hook.d.ts +6 -0
- package/dist/commands/hook.d.ts.map +1 -0
- package/dist/commands/hook.js +106 -0
- package/dist/commands/hook.js.map +1 -0
- package/dist/commands/login.d.ts +17 -0
- package/dist/commands/login.d.ts.map +1 -1
- package/dist/commands/login.js +170 -65
- package/dist/commands/login.js.map +1 -1
- package/dist/commands/orgs.d.ts +3 -0
- package/dist/commands/orgs.d.ts.map +1 -0
- package/dist/commands/orgs.js +102 -0
- package/dist/commands/orgs.js.map +1 -0
- package/dist/commands/push.d.ts.map +1 -1
- package/dist/commands/push.js +29 -6
- package/dist/commands/push.js.map +1 -1
- package/dist/commands/sessions.d.ts +3 -0
- package/dist/commands/sessions.d.ts.map +1 -0
- package/dist/commands/sessions.js +139 -0
- package/dist/commands/sessions.js.map +1 -0
- package/dist/commands/setup.d.ts +3 -0
- package/dist/commands/setup.d.ts.map +1 -0
- package/dist/commands/setup.js +58 -0
- package/dist/commands/setup.js.map +1 -0
- package/dist/commands/skills.d.ts +12 -0
- package/dist/commands/skills.d.ts.map +1 -0
- package/dist/commands/skills.js +171 -0
- package/dist/commands/skills.js.map +1 -0
- package/dist/commands/sync.d.ts.map +1 -1
- package/dist/commands/sync.js +51 -49
- package/dist/commands/sync.js.map +1 -1
- package/dist/commands/users.d.ts +13 -0
- package/dist/commands/users.d.ts.map +1 -0
- package/dist/commands/users.js +205 -0
- package/dist/commands/users.js.map +1 -0
- package/dist/commands/whoami.d.ts +21 -0
- package/dist/commands/whoami.d.ts.map +1 -0
- package/dist/commands/whoami.js +77 -0
- package/dist/commands/whoami.js.map +1 -0
- package/dist/lib/api-client.d.ts +64 -2
- package/dist/lib/api-client.d.ts.map +1 -1
- package/dist/lib/api-client.js +32 -7
- package/dist/lib/api-client.js.map +1 -1
- package/dist/lib/auth.d.ts +43 -6
- package/dist/lib/auth.d.ts.map +1 -1
- package/dist/lib/auth.js +106 -25
- package/dist/lib/auth.js.map +1 -1
- package/dist/lib/config-files.d.ts +6 -0
- package/dist/lib/config-files.d.ts.map +1 -0
- package/dist/lib/config-files.js +27 -0
- package/dist/lib/config-files.js.map +1 -0
- package/dist/lib/config.d.ts +13 -7
- package/dist/lib/config.d.ts.map +1 -1
- package/dist/lib/config.js +22 -8
- package/dist/lib/config.js.map +1 -1
- package/dist/lib/copilot-export.d.ts +31 -0
- package/dist/lib/copilot-export.d.ts.map +1 -0
- package/dist/lib/copilot-export.js +129 -0
- package/dist/lib/copilot-export.js.map +1 -0
- package/dist/lib/discovery.d.ts +60 -2
- package/dist/lib/discovery.d.ts.map +1 -1
- package/dist/lib/discovery.js +187 -15
- package/dist/lib/discovery.js.map +1 -1
- package/dist/lib/hook-discovery.d.ts +43 -0
- package/dist/lib/hook-discovery.d.ts.map +1 -0
- package/dist/lib/hook-discovery.js +90 -0
- package/dist/lib/hook-discovery.js.map +1 -0
- package/dist/lib/hook-input.d.ts +36 -0
- package/dist/lib/hook-input.d.ts.map +1 -0
- package/dist/lib/hook-input.js +161 -0
- package/dist/lib/hook-input.js.map +1 -0
- package/dist/lib/hook-runner.d.ts +48 -0
- package/dist/lib/hook-runner.d.ts.map +1 -0
- package/dist/lib/hook-runner.js +306 -0
- package/dist/lib/hook-runner.js.map +1 -0
- package/dist/lib/http.d.ts +18 -0
- package/dist/lib/http.d.ts.map +1 -0
- package/dist/lib/http.js +54 -0
- package/dist/lib/http.js.map +1 -0
- package/dist/lib/opencode-export.d.ts +22 -0
- package/dist/lib/opencode-export.d.ts.map +1 -0
- package/dist/lib/opencode-export.js +53 -0
- package/dist/lib/opencode-export.js.map +1 -0
- package/dist/lib/output.d.ts +27 -0
- package/dist/lib/output.d.ts.map +1 -0
- package/dist/lib/output.js +74 -0
- package/dist/lib/output.js.map +1 -0
- package/dist/lib/preflight.d.ts +35 -0
- package/dist/lib/preflight.d.ts.map +1 -0
- package/dist/lib/preflight.js +54 -0
- package/dist/lib/preflight.js.map +1 -0
- package/dist/lib/repo-binding.d.ts +43 -0
- package/dist/lib/repo-binding.d.ts.map +1 -0
- package/dist/lib/repo-binding.js +158 -0
- package/dist/lib/repo-binding.js.map +1 -0
- package/dist/lib/repo-identity.d.ts +29 -0
- package/dist/lib/repo-identity.d.ts.map +1 -0
- package/dist/lib/repo-identity.js +113 -0
- package/dist/lib/repo-identity.js.map +1 -0
- package/dist/lib/setup-hooks.d.ts +41 -0
- package/dist/lib/setup-hooks.d.ts.map +1 -0
- package/dist/lib/setup-hooks.js +276 -0
- package/dist/lib/setup-hooks.js.map +1 -0
- package/dist/lib/setup.d.ts +47 -0
- package/dist/lib/setup.d.ts.map +1 -0
- package/dist/lib/setup.js +179 -0
- package/dist/lib/setup.js.map +1 -0
- package/dist/lib/skill-batches.d.ts +16 -0
- package/dist/lib/skill-batches.d.ts.map +1 -0
- package/dist/lib/skill-batches.js +35 -0
- package/dist/lib/skill-batches.js.map +1 -0
- package/dist/lib/skill-files.d.ts +4 -0
- package/dist/lib/skill-files.d.ts.map +1 -0
- package/dist/lib/skill-files.js +36 -0
- package/dist/lib/skill-files.js.map +1 -0
- package/dist/lib/skill-fingerprint.d.ts +55 -0
- package/dist/lib/skill-fingerprint.d.ts.map +1 -0
- package/dist/lib/skill-fingerprint.js +204 -0
- package/dist/lib/skill-fingerprint.js.map +1 -0
- package/dist/lib/skills-discovery.d.ts +57 -0
- package/dist/lib/skills-discovery.d.ts.map +1 -0
- package/dist/lib/skills-discovery.js +157 -0
- package/dist/lib/skills-discovery.js.map +1 -0
- package/dist/lib/skills-sync.d.ts +66 -0
- package/dist/lib/skills-sync.d.ts.map +1 -0
- package/dist/lib/skills-sync.js +251 -0
- package/dist/lib/skills-sync.js.map +1 -0
- package/dist/lib/sync-runner.d.ts +56 -0
- package/dist/lib/sync-runner.d.ts.map +1 -0
- package/dist/lib/sync-runner.js +106 -0
- package/dist/lib/sync-runner.js.map +1 -0
- package/dist/lib/sync-state.d.ts +36 -6
- package/dist/lib/sync-state.d.ts.map +1 -1
- package/dist/lib/sync-state.js +41 -11
- package/dist/lib/sync-state.js.map +1 -1
- package/package.json +16 -8
|
@@ -0,0 +1,55 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Content fingerprint for a skill folder plus a minimal SKILL.md front-matter
|
|
3
|
+
* parser. The fingerprint covers the whole tree (skills ship helper scripts
|
|
4
|
+
* and templates next to SKILL.md), so any edit anywhere in the folder is a
|
|
5
|
+
* change; the manifest it is built from travels with the upload so a later
|
|
6
|
+
* write-back can tell which file drifted.
|
|
7
|
+
*/
|
|
8
|
+
export interface SkillFileEntry {
|
|
9
|
+
/** Path relative to the skill directory, posix separators. */
|
|
10
|
+
path: string;
|
|
11
|
+
size: number;
|
|
12
|
+
sha256: string;
|
|
13
|
+
/** The file's bytes, kept so the upload can carry them (see skill-files.ts). */
|
|
14
|
+
bytes: Buffer;
|
|
15
|
+
}
|
|
16
|
+
export interface SkillFingerprint {
|
|
17
|
+
/** sha256 over the sorted manifest (`<path>\0<sha256>\n` per file). */
|
|
18
|
+
treeHash: string;
|
|
19
|
+
files: SkillFileEntry[];
|
|
20
|
+
/** Newest mtime across the tree — the source-side "last modified" time. */
|
|
21
|
+
modifiedAt: Date;
|
|
22
|
+
/** Files left out of the manifest (and so never uploaded) because they exceed MAX_FILE_BYTES. */
|
|
23
|
+
skippedPaths: string[];
|
|
24
|
+
/** Files hashed (`files` may be a prefix of them when the tree is larger than MAX_FILES). */
|
|
25
|
+
fileCount: number;
|
|
26
|
+
/** The walk stopped early (WALK_FILE_BUDGET / WALK_BYTE_BUDGET): the hash covers a prefix of the tree. */
|
|
27
|
+
truncated: boolean;
|
|
28
|
+
}
|
|
29
|
+
export declare function fingerprintSkillDir(dir: string): SkillFingerprint;
|
|
30
|
+
export interface ParsedSkillMarkdown {
|
|
31
|
+
/** Top-level front-matter fields, values as written (block scalars joined). */
|
|
32
|
+
frontmatter: Record<string, string>;
|
|
33
|
+
/**
|
|
34
|
+
* The verbatim text between the opening `---` line and the closing `---`
|
|
35
|
+
* line (CRLF normalised, nothing else touched); absent when the file has
|
|
36
|
+
* no front-matter block. The server parses this itself, so nothing the
|
|
37
|
+
* flat `frontmatter` map cannot express is lost.
|
|
38
|
+
*/
|
|
39
|
+
frontmatterRaw?: string;
|
|
40
|
+
/** Markdown after the front-matter block (the whole file when there is none). */
|
|
41
|
+
body: string;
|
|
42
|
+
name?: string;
|
|
43
|
+
description?: string;
|
|
44
|
+
/** Things the author probably wants to know about (e.g. an unterminated front-matter block). */
|
|
45
|
+
warnings: string[];
|
|
46
|
+
}
|
|
47
|
+
/**
|
|
48
|
+
* Parse SKILL.md front-matter without a YAML dependency. Handles what skill
|
|
49
|
+
* files actually use: `key: value` scalars (optionally quoted), `|` / `>`
|
|
50
|
+
* block scalars, and nested blocks (`metadata:` maps, lists), which are kept
|
|
51
|
+
* as their raw indented text. Anything unparseable is left out rather than
|
|
52
|
+
* failing the sync.
|
|
53
|
+
*/
|
|
54
|
+
export declare function parseSkillMarkdown(raw: string): ParsedSkillMarkdown;
|
|
55
|
+
//# sourceMappingURL=skill-fingerprint.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"skill-fingerprint.d.ts","sourceRoot":"","sources":["../../src/lib/skill-fingerprint.ts"],"names":[],"mappings":"AAIA;;;;;;GAMG;AAEH,MAAM,WAAW,cAAc;IAC7B,8DAA8D;IAC9D,IAAI,EAAE,MAAM,CAAA;IACZ,IAAI,EAAE,MAAM,CAAA;IACZ,MAAM,EAAE,MAAM,CAAA;IACd,gFAAgF;IAChF,KAAK,EAAE,MAAM,CAAA;CACd;AAED,MAAM,WAAW,gBAAgB;IAC/B,uEAAuE;IACvE,QAAQ,EAAE,MAAM,CAAA;IAChB,KAAK,EAAE,cAAc,EAAE,CAAA;IACvB,2EAA2E;IAC3E,UAAU,EAAE,IAAI,CAAA;IAChB,iGAAiG;IACjG,YAAY,EAAE,MAAM,EAAE,CAAA;IACtB,6FAA6F;IAC7F,SAAS,EAAE,MAAM,CAAA;IACjB,0GAA0G;IAC1G,SAAS,EAAE,OAAO,CAAA;CACnB;AAgBD,wBAAgB,mBAAmB,CAAC,GAAG,EAAE,MAAM,GAAG,gBAAgB,CAgEjE;AAuBD,MAAM,WAAW,mBAAmB;IAClC,+EAA+E;IAC/E,WAAW,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAA;IACnC;;;;;OAKG;IACH,cAAc,CAAC,EAAE,MAAM,CAAA;IACvB,iFAAiF;IACjF,IAAI,EAAE,MAAM,CAAA;IACZ,IAAI,CAAC,EAAE,MAAM,CAAA;IACb,WAAW,CAAC,EAAE,MAAM,CAAA;IACpB,gGAAgG;IAChG,QAAQ,EAAE,MAAM,EAAE,CAAA;CACnB;AAED;;;;;;GAMG;AACH,wBAAgB,kBAAkB,CAAC,GAAG,EAAE,MAAM,GAAG,mBAAmB,CAqCnE"}
|
|
@@ -0,0 +1,204 @@
|
|
|
1
|
+
import { createHash } from 'node:crypto';
|
|
2
|
+
import { readdirSync, readFileSync, realpathSync, statSync } from 'node:fs';
|
|
3
|
+
import { join } from 'node:path';
|
|
4
|
+
const IGNORED_DIRS = new Set(['.git', 'node_modules', '__pycache__', '.venv', 'venv']);
|
|
5
|
+
const IGNORED_FILES = new Set(['.DS_Store', 'Thumbs.db']);
|
|
6
|
+
/** Anything larger is not skill content (binaries, datasets); left out of the manifest. */
|
|
7
|
+
const MAX_FILE_BYTES = 1024 * 1024;
|
|
8
|
+
/** Bound on manifest size; the server rejects more. */
|
|
9
|
+
const MAX_FILES = 500;
|
|
10
|
+
/**
|
|
11
|
+
* Hard stop for the walk so a skill that symlinks into a large tree cannot
|
|
12
|
+
* stall the session-start hook: after this many files or bytes the walk ends
|
|
13
|
+
* and the fingerprint is flagged `truncated`.
|
|
14
|
+
*/
|
|
15
|
+
const WALK_FILE_BUDGET = 2000;
|
|
16
|
+
const WALK_BYTE_BUDGET = 32 * 1024 * 1024;
|
|
17
|
+
export function fingerprintSkillDir(dir) {
|
|
18
|
+
const files = [];
|
|
19
|
+
const skippedPaths = [];
|
|
20
|
+
let modifiedAt = 0;
|
|
21
|
+
let bytes = 0;
|
|
22
|
+
let truncated = false;
|
|
23
|
+
const seenDirs = new Set();
|
|
24
|
+
const overBudget = () => {
|
|
25
|
+
if (files.length < WALK_FILE_BUDGET && bytes < WALK_BYTE_BUDGET)
|
|
26
|
+
return false;
|
|
27
|
+
truncated = true;
|
|
28
|
+
return true;
|
|
29
|
+
};
|
|
30
|
+
const walk = (current, prefix) => {
|
|
31
|
+
const real = canonical(current);
|
|
32
|
+
if (seenDirs.has(real))
|
|
33
|
+
return; // symlink cycle
|
|
34
|
+
seenDirs.add(real);
|
|
35
|
+
for (const name of listSorted(current)) {
|
|
36
|
+
if (overBudget())
|
|
37
|
+
return;
|
|
38
|
+
const full = join(current, name);
|
|
39
|
+
let stat;
|
|
40
|
+
try {
|
|
41
|
+
stat = statSync(full);
|
|
42
|
+
}
|
|
43
|
+
catch {
|
|
44
|
+
continue; // dangling symlink or vanished file
|
|
45
|
+
}
|
|
46
|
+
if (stat.isDirectory()) {
|
|
47
|
+
if (!IGNORED_DIRS.has(name))
|
|
48
|
+
walk(full, `${prefix}${name}/`);
|
|
49
|
+
continue;
|
|
50
|
+
}
|
|
51
|
+
if (!stat.isFile() || IGNORED_FILES.has(name))
|
|
52
|
+
continue;
|
|
53
|
+
if (stat.size > MAX_FILE_BYTES) {
|
|
54
|
+
skippedPaths.push(`${prefix}${name}`);
|
|
55
|
+
continue;
|
|
56
|
+
}
|
|
57
|
+
let content;
|
|
58
|
+
try {
|
|
59
|
+
content = readFileSync(full);
|
|
60
|
+
}
|
|
61
|
+
catch {
|
|
62
|
+
continue; // unreadable helper file: SKILL.md itself is read (and fails loudly) by the caller
|
|
63
|
+
}
|
|
64
|
+
bytes += content.length;
|
|
65
|
+
modifiedAt = Math.max(modifiedAt, stat.mtimeMs);
|
|
66
|
+
files.push({
|
|
67
|
+
path: `${prefix}${name}`,
|
|
68
|
+
size: stat.size,
|
|
69
|
+
sha256: sha256(content),
|
|
70
|
+
bytes: content,
|
|
71
|
+
});
|
|
72
|
+
}
|
|
73
|
+
};
|
|
74
|
+
walk(dir, '');
|
|
75
|
+
files.sort((a, b) => (a.path < b.path ? -1 : a.path > b.path ? 1 : 0));
|
|
76
|
+
const manifest = files.map((f) => `${f.path}\0${f.sha256}\n`).join('');
|
|
77
|
+
return {
|
|
78
|
+
treeHash: sha256(Buffer.from(manifest)),
|
|
79
|
+
files: files.slice(0, MAX_FILES),
|
|
80
|
+
modifiedAt: new Date(modifiedAt || Date.now()),
|
|
81
|
+
skippedPaths,
|
|
82
|
+
fileCount: files.length,
|
|
83
|
+
truncated,
|
|
84
|
+
};
|
|
85
|
+
}
|
|
86
|
+
/** Directory entries in a stable order; an unreadable directory contributes nothing. */
|
|
87
|
+
function listSorted(dir) {
|
|
88
|
+
try {
|
|
89
|
+
return readdirSync(dir).sort();
|
|
90
|
+
}
|
|
91
|
+
catch {
|
|
92
|
+
return [];
|
|
93
|
+
}
|
|
94
|
+
}
|
|
95
|
+
function sha256(content) {
|
|
96
|
+
return createHash('sha256').update(content).digest('hex');
|
|
97
|
+
}
|
|
98
|
+
function canonical(path) {
|
|
99
|
+
try {
|
|
100
|
+
return realpathSync(path);
|
|
101
|
+
}
|
|
102
|
+
catch {
|
|
103
|
+
return path;
|
|
104
|
+
}
|
|
105
|
+
}
|
|
106
|
+
/**
|
|
107
|
+
* Parse SKILL.md front-matter without a YAML dependency. Handles what skill
|
|
108
|
+
* files actually use: `key: value` scalars (optionally quoted), `|` / `>`
|
|
109
|
+
* block scalars, and nested blocks (`metadata:` maps, lists), which are kept
|
|
110
|
+
* as their raw indented text. Anything unparseable is left out rather than
|
|
111
|
+
* failing the sync.
|
|
112
|
+
*/
|
|
113
|
+
export function parseSkillMarkdown(raw) {
|
|
114
|
+
const text = raw.replace(/\r\n/g, '\n');
|
|
115
|
+
const frontmatter = {};
|
|
116
|
+
const warnings = [];
|
|
117
|
+
if (!text.startsWith('---\n'))
|
|
118
|
+
return { frontmatter, body: text, warnings };
|
|
119
|
+
// The closing line must be exactly `---` (trailing whitespace allowed).
|
|
120
|
+
const close = /\n---[ \t]*(?:\n|$)/.exec(text.slice(4));
|
|
121
|
+
const end = close ? close.index + 4 : -1;
|
|
122
|
+
if (end === -1) {
|
|
123
|
+
warnings.push('front-matter block is not terminated by a `---` line; treating the whole file as body');
|
|
124
|
+
return { frontmatter, body: text, warnings };
|
|
125
|
+
}
|
|
126
|
+
const block = text.slice(4, end);
|
|
127
|
+
const afterClose = text.indexOf('\n', end + 1);
|
|
128
|
+
const body = afterClose === -1 ? '' : text.slice(afterClose + 1);
|
|
129
|
+
const lines = block.split('\n');
|
|
130
|
+
for (let i = 0; i < lines.length; i++) {
|
|
131
|
+
const line = lines[i] ?? '';
|
|
132
|
+
const match = /^([A-Za-z0-9_-]+):(?:[ \t]+(.*))?$/.exec(line);
|
|
133
|
+
if (!match)
|
|
134
|
+
continue;
|
|
135
|
+
const key = match[1] ?? '';
|
|
136
|
+
const inline = (match[2] ?? '').trim();
|
|
137
|
+
const { value, consumed } = readValue(inline, lines, i + 1);
|
|
138
|
+
frontmatter[key] = value;
|
|
139
|
+
i += consumed;
|
|
140
|
+
}
|
|
141
|
+
const name = frontmatter['name']?.trim() || undefined;
|
|
142
|
+
const description = frontmatter['description']?.trim() || undefined;
|
|
143
|
+
if (!name)
|
|
144
|
+
warnings.push('front-matter has no `name`; using the folder name');
|
|
145
|
+
if (!description)
|
|
146
|
+
warnings.push('front-matter has no `description`');
|
|
147
|
+
return { frontmatter, frontmatterRaw: block, body, name, description, warnings };
|
|
148
|
+
}
|
|
149
|
+
/** Resolve a front-matter value: inline scalar, block scalar, or nested block. */
|
|
150
|
+
function readValue(inline, lines, from) {
|
|
151
|
+
const continuation = collectIndented(lines, from);
|
|
152
|
+
if (inline === '|' || inline === '|-' || inline === '>' || inline === '>-') {
|
|
153
|
+
const stripped = dedent(continuation.lines);
|
|
154
|
+
const joined = inline.startsWith('|') ? stripped.join('\n') : foldLines(stripped);
|
|
155
|
+
return { value: joined.trim(), consumed: continuation.count };
|
|
156
|
+
}
|
|
157
|
+
if (inline === '' && continuation.count > 0) {
|
|
158
|
+
return { value: dedent(continuation.lines).join('\n'), consumed: continuation.count };
|
|
159
|
+
}
|
|
160
|
+
return { value: scalar(inline), consumed: 0 };
|
|
161
|
+
}
|
|
162
|
+
function collectIndented(lines, from) {
|
|
163
|
+
const out = [];
|
|
164
|
+
let i = from;
|
|
165
|
+
while (i < lines.length) {
|
|
166
|
+
const line = lines[i] ?? '';
|
|
167
|
+
if (line.trim() !== '' && !/^[ \t]/.test(line))
|
|
168
|
+
break;
|
|
169
|
+
out.push(line);
|
|
170
|
+
i++;
|
|
171
|
+
}
|
|
172
|
+
// Trailing blank lines belong to the next key, not the block.
|
|
173
|
+
while (out.length > 0 && (out[out.length - 1] ?? '').trim() === '')
|
|
174
|
+
out.pop();
|
|
175
|
+
return { lines: out, count: out.length };
|
|
176
|
+
}
|
|
177
|
+
function dedent(lines) {
|
|
178
|
+
const indents = lines
|
|
179
|
+
.filter((l) => l.trim() !== '')
|
|
180
|
+
.map((l) => /^[ \t]*/.exec(l)?.[0].length ?? 0);
|
|
181
|
+
const min = indents.length > 0 ? Math.min(...indents) : 0;
|
|
182
|
+
return lines.map((l) => l.slice(Math.min(min, /^[ \t]*/.exec(l)?.[0].length ?? 0)));
|
|
183
|
+
}
|
|
184
|
+
/** YAML folded style: newlines become spaces, blank lines become newlines. */
|
|
185
|
+
function foldLines(lines) {
|
|
186
|
+
return lines
|
|
187
|
+
.join('\n')
|
|
188
|
+
.split(/\n{2,}/)
|
|
189
|
+
.map((paragraph) => paragraph.split('\n').join(' ').trim())
|
|
190
|
+
.join('\n');
|
|
191
|
+
}
|
|
192
|
+
/** Inline scalar: strip a trailing comment and surrounding quotes. */
|
|
193
|
+
function scalar(value) {
|
|
194
|
+
const doubleQuoted = /^"((?:[^"\\]|\\.)*)"(?:\s+#.*)?$/.exec(value);
|
|
195
|
+
if (doubleQuoted) {
|
|
196
|
+
return (doubleQuoted[1] ?? '').replace(/\\"/g, '"').replace(/\\n/g, '\n').replace(/\\\\/g, '\\');
|
|
197
|
+
}
|
|
198
|
+
const singleQuoted = /^'((?:[^']|'')*)'(?:\s+#.*)?$/.exec(value);
|
|
199
|
+
if (singleQuoted)
|
|
200
|
+
return (singleQuoted[1] ?? '').replace(/''/g, "'");
|
|
201
|
+
const hash = value.indexOf(' #');
|
|
202
|
+
return (hash === -1 ? value : value.slice(0, hash)).trim();
|
|
203
|
+
}
|
|
204
|
+
//# sourceMappingURL=skill-fingerprint.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"skill-fingerprint.js","sourceRoot":"","sources":["../../src/lib/skill-fingerprint.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,57 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Where coding-agent harnesses look for skills. A skill is a directory that
|
|
3
|
+
* directly contains a `SKILL.md` (the Agent Skills format, agentskills.io).
|
|
4
|
+
* Every harness reads its own `.<tool>/skills` directory; most also read
|
|
5
|
+
* `.agents/skills` (the cross-client convention) and `.claude/skills` for
|
|
6
|
+
* compatibility, so the same folder is routinely reachable from several of
|
|
7
|
+
* these — often through symlinks. Discovery de-duplicates by real path.
|
|
8
|
+
*/
|
|
9
|
+
export type SkillScope = 'user' | 'project';
|
|
10
|
+
export interface SkillLocation {
|
|
11
|
+
/** Harness that reads this directory. */
|
|
12
|
+
harness: string;
|
|
13
|
+
/** Directory relative to the scope root (home dir or repo root), posix separators. */
|
|
14
|
+
dir: string;
|
|
15
|
+
}
|
|
16
|
+
/**
|
|
17
|
+
* Order is load-bearing: when a skill's real directory lies outside every
|
|
18
|
+
* scanned location (a symlink to somewhere else) the first location that
|
|
19
|
+
* sees it names its `relativePath`, which becomes its ledger key and server
|
|
20
|
+
* identity. Append new harnesses at the end; never reorder.
|
|
21
|
+
*/
|
|
22
|
+
/** User-level skill directories, relative to $HOME. */
|
|
23
|
+
export declare const USER_SKILL_LOCATIONS: readonly SkillLocation[];
|
|
24
|
+
/** Repo-level skill directories, relative to the repository root. */
|
|
25
|
+
export declare const PROJECT_SKILL_LOCATIONS: readonly SkillLocation[];
|
|
26
|
+
export declare const SKILL_FILE = "SKILL.md";
|
|
27
|
+
export interface DiscoveredSkill {
|
|
28
|
+
scope: SkillScope;
|
|
29
|
+
/** Absolute path of the skill directory as found (may sit behind a symlink). */
|
|
30
|
+
dir: string;
|
|
31
|
+
/** Canonical absolute path (symlinks resolved) — the de-dupe key within a scope. */
|
|
32
|
+
realDir: string;
|
|
33
|
+
/** Skill directory relative to the scope root, posix separators. */
|
|
34
|
+
relativePath: string;
|
|
35
|
+
/** Every relative path the skill was found at (symlink aliases), `relativePath` first. */
|
|
36
|
+
locations: string[];
|
|
37
|
+
/** Harnesses whose directories contain the skill. */
|
|
38
|
+
harnesses: string[];
|
|
39
|
+
/** Directory basename; the spec says the frontmatter `name` must match it. */
|
|
40
|
+
folderName: string;
|
|
41
|
+
}
|
|
42
|
+
export interface DiscoverSkillsOptions {
|
|
43
|
+
scope: SkillScope;
|
|
44
|
+
/** Home directory (user scope) or repository root (project scope). */
|
|
45
|
+
rootDir: string;
|
|
46
|
+
/** Defaults to the scope's built-in location table. */
|
|
47
|
+
locations?: readonly SkillLocation[];
|
|
48
|
+
}
|
|
49
|
+
/**
|
|
50
|
+
* Discover skills under one scope root. Skill directories sit directly under
|
|
51
|
+
* a location (`.claude/skills/<name>/SKILL.md`); up to two levels of grouping
|
|
52
|
+
* are allowed so grouped layouts (`~/.claude/skills/synced/<uuid>/<name>`,
|
|
53
|
+
* Gemini's nested dirs) are found too. Dot-directories are skipped
|
|
54
|
+
* (`~/.codex/skills/.system` holds Codex's bundled skills, not the user's).
|
|
55
|
+
*/
|
|
56
|
+
export declare function discoverSkills(options: DiscoverSkillsOptions): DiscoveredSkill[];
|
|
57
|
+
//# sourceMappingURL=skills-discovery.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"skills-discovery.d.ts","sourceRoot":"","sources":["../../src/lib/skills-discovery.ts"],"names":[],"mappings":"AAGA;;;;;;;GAOG;AAEH,MAAM,MAAM,UAAU,GAAG,MAAM,GAAG,SAAS,CAAA;AAE3C,MAAM,WAAW,aAAa;IAC5B,yCAAyC;IACzC,OAAO,EAAE,MAAM,CAAA;IACf,sFAAsF;IACtF,GAAG,EAAE,MAAM,CAAA;CACZ;AAED;;;;;GAKG;AAEH,uDAAuD;AACvD,eAAO,MAAM,oBAAoB,EAAE,SAAS,aAAa,EAcxD,CAAA;AAED,qEAAqE;AACrE,eAAO,MAAM,uBAAuB,EAAE,SAAS,aAAa,EAa3D,CAAA;AAED,eAAO,MAAM,UAAU,aAAa,CAAA;AAEpC,MAAM,WAAW,eAAe;IAC9B,KAAK,EAAE,UAAU,CAAA;IACjB,gFAAgF;IAChF,GAAG,EAAE,MAAM,CAAA;IACX,oFAAoF;IACpF,OAAO,EAAE,MAAM,CAAA;IACf,oEAAoE;IACpE,YAAY,EAAE,MAAM,CAAA;IACpB,0FAA0F;IAC1F,SAAS,EAAE,MAAM,EAAE,CAAA;IACnB,qDAAqD;IACrD,SAAS,EAAE,MAAM,EAAE,CAAA;IACnB,8EAA8E;IAC9E,UAAU,EAAE,MAAM,CAAA;CACnB;AAED,MAAM,WAAW,qBAAqB;IACpC,KAAK,EAAE,UAAU,CAAA;IACjB,sEAAsE;IACtE,OAAO,EAAE,MAAM,CAAA;IACf,uDAAuD;IACvD,SAAS,CAAC,EAAE,SAAS,aAAa,EAAE,CAAA;CACrC;AAED;;;;;;GAMG;AACH,wBAAgB,cAAc,CAAC,OAAO,EAAE,qBAAqB,GAAG,eAAe,EAAE,CAyChF"}
|
|
@@ -0,0 +1,157 @@
|
|
|
1
|
+
import { existsSync, readdirSync, realpathSync, statSync } from 'node:fs';
|
|
2
|
+
import { basename, join } from 'node:path';
|
|
3
|
+
/**
|
|
4
|
+
* Order is load-bearing: when a skill's real directory lies outside every
|
|
5
|
+
* scanned location (a symlink to somewhere else) the first location that
|
|
6
|
+
* sees it names its `relativePath`, which becomes its ledger key and server
|
|
7
|
+
* identity. Append new harnesses at the end; never reorder.
|
|
8
|
+
*/
|
|
9
|
+
/** User-level skill directories, relative to $HOME. */
|
|
10
|
+
export const USER_SKILL_LOCATIONS = [
|
|
11
|
+
{ harness: 'claude', dir: '.claude/skills' },
|
|
12
|
+
{ harness: 'agents', dir: '.agents/skills' },
|
|
13
|
+
{ harness: 'codex', dir: '.codex/skills' },
|
|
14
|
+
{ harness: 'cursor', dir: '.cursor/skills' },
|
|
15
|
+
{ harness: 'gemini', dir: '.gemini/skills' },
|
|
16
|
+
{ harness: 'copilot', dir: '.copilot/skills' },
|
|
17
|
+
{ harness: 'opencode', dir: '.config/opencode/skills' },
|
|
18
|
+
{ harness: 'amp', dir: '.config/agents/skills' },
|
|
19
|
+
{ harness: 'windsurf', dir: '.codeium/windsurf/skills' },
|
|
20
|
+
{ harness: 'grok', dir: '.grok/skills' },
|
|
21
|
+
{ harness: 'kiro', dir: '.kiro/skills' },
|
|
22
|
+
{ harness: 'cline', dir: '.cline/skills' },
|
|
23
|
+
{ harness: 'factory', dir: '.factory/skills' },
|
|
24
|
+
];
|
|
25
|
+
/** Repo-level skill directories, relative to the repository root. */
|
|
26
|
+
export const PROJECT_SKILL_LOCATIONS = [
|
|
27
|
+
{ harness: 'claude', dir: '.claude/skills' },
|
|
28
|
+
{ harness: 'agents', dir: '.agents/skills' },
|
|
29
|
+
{ harness: 'codex', dir: '.codex/skills' },
|
|
30
|
+
{ harness: 'cursor', dir: '.cursor/skills' },
|
|
31
|
+
{ harness: 'gemini', dir: '.gemini/skills' },
|
|
32
|
+
{ harness: 'copilot', dir: '.github/skills' },
|
|
33
|
+
{ harness: 'opencode', dir: '.opencode/skills' },
|
|
34
|
+
{ harness: 'windsurf', dir: '.windsurf/skills' },
|
|
35
|
+
{ harness: 'grok', dir: '.grok/skills' },
|
|
36
|
+
{ harness: 'kiro', dir: '.kiro/skills' },
|
|
37
|
+
{ harness: 'cline', dir: '.cline/skills' },
|
|
38
|
+
{ harness: 'factory', dir: '.factory/skills' },
|
|
39
|
+
];
|
|
40
|
+
export const SKILL_FILE = 'SKILL.md';
|
|
41
|
+
/**
|
|
42
|
+
* Discover skills under one scope root. Skill directories sit directly under
|
|
43
|
+
* a location (`.claude/skills/<name>/SKILL.md`); up to two levels of grouping
|
|
44
|
+
* are allowed so grouped layouts (`~/.claude/skills/synced/<uuid>/<name>`,
|
|
45
|
+
* Gemini's nested dirs) are found too. Dot-directories are skipped
|
|
46
|
+
* (`~/.codex/skills/.system` holds Codex's bundled skills, not the user's).
|
|
47
|
+
*/
|
|
48
|
+
export function discoverSkills(options) {
|
|
49
|
+
const { scope, rootDir } = options;
|
|
50
|
+
const locations = options.locations ?? (scope === 'user' ? USER_SKILL_LOCATIONS : PROJECT_SKILL_LOCATIONS);
|
|
51
|
+
const byRealDir = new Map();
|
|
52
|
+
// A sighting is the real location (not a symlink alias) when its canonical
|
|
53
|
+
// path is exactly the canonical root plus its relative path.
|
|
54
|
+
const canonicalRoot = canonical(rootDir);
|
|
55
|
+
const primaryIsReal = new Map();
|
|
56
|
+
for (const location of locations) {
|
|
57
|
+
const base = join(rootDir, ...location.dir.split('/'));
|
|
58
|
+
if (!isDirectory(base))
|
|
59
|
+
continue;
|
|
60
|
+
for (const relative of listSkillDirs(base)) {
|
|
61
|
+
const dir = join(base, ...relative.split('/'));
|
|
62
|
+
const realDir = canonical(dir);
|
|
63
|
+
const relativePath = `${location.dir}/${relative}`;
|
|
64
|
+
const isReal = realDir === join(canonicalRoot, ...relativePath.split('/'));
|
|
65
|
+
const existing = byRealDir.get(realDir);
|
|
66
|
+
if (existing) {
|
|
67
|
+
if (isReal && !primaryIsReal.get(realDir)) {
|
|
68
|
+
promote(existing, { dir, relativePath });
|
|
69
|
+
primaryIsReal.set(realDir, true);
|
|
70
|
+
}
|
|
71
|
+
addSighting(existing, relativePath, location.harness);
|
|
72
|
+
continue;
|
|
73
|
+
}
|
|
74
|
+
primaryIsReal.set(realDir, isReal);
|
|
75
|
+
byRealDir.set(realDir, {
|
|
76
|
+
scope,
|
|
77
|
+
dir,
|
|
78
|
+
realDir,
|
|
79
|
+
relativePath,
|
|
80
|
+
locations: [relativePath],
|
|
81
|
+
harnesses: [location.harness],
|
|
82
|
+
folderName: basename(realDir),
|
|
83
|
+
});
|
|
84
|
+
}
|
|
85
|
+
}
|
|
86
|
+
return [...byRealDir.values()].sort((a, b) => a.relativePath.localeCompare(b.relativePath));
|
|
87
|
+
}
|
|
88
|
+
/** Record another path / harness the same skill directory was seen through. */
|
|
89
|
+
function addSighting(skill, relativePath, harness) {
|
|
90
|
+
if (!skill.locations.includes(relativePath))
|
|
91
|
+
skill.locations.push(relativePath);
|
|
92
|
+
if (!skill.harnesses.includes(harness))
|
|
93
|
+
skill.harnesses.push(harness);
|
|
94
|
+
}
|
|
95
|
+
/** Make the real directory (not a symlink alias) the canonical path of a skill. */
|
|
96
|
+
function promote(skill, real) {
|
|
97
|
+
skill.dir = real.dir;
|
|
98
|
+
skill.relativePath = real.relativePath;
|
|
99
|
+
skill.locations = [real.relativePath, ...skill.locations.filter((l) => l !== real.relativePath)];
|
|
100
|
+
}
|
|
101
|
+
/** Grouping levels scanned below a location root (`<group>/<subgroup>/<name>`). */
|
|
102
|
+
const MAX_GROUP_DEPTH = 2;
|
|
103
|
+
/**
|
|
104
|
+
* Relative skill dirs (posix) under a location root: `<name>`, `<group>/<name>`
|
|
105
|
+
* or `<group>/<subgroup>/<name>`. A skill directory is a leaf — its subfolders
|
|
106
|
+
* are its files, never nested skills — and the walk stops at `MAX_GROUP_DEPTH`.
|
|
107
|
+
*/
|
|
108
|
+
function listSkillDirs(base, depth = 0) {
|
|
109
|
+
const found = [];
|
|
110
|
+
for (const entry of listVisibleDirs(base)) {
|
|
111
|
+
const dir = join(base, entry);
|
|
112
|
+
if (hasSkillFile(dir)) {
|
|
113
|
+
found.push(entry);
|
|
114
|
+
}
|
|
115
|
+
else if (depth < MAX_GROUP_DEPTH) {
|
|
116
|
+
for (const nested of listSkillDirs(dir, depth + 1))
|
|
117
|
+
found.push(`${entry}/${nested}`);
|
|
118
|
+
}
|
|
119
|
+
}
|
|
120
|
+
return found;
|
|
121
|
+
}
|
|
122
|
+
function listVisibleDirs(dir) {
|
|
123
|
+
try {
|
|
124
|
+
return readdirSync(dir)
|
|
125
|
+
.filter((name) => !name.startsWith('.'))
|
|
126
|
+
.filter((name) => isDirectory(join(dir, name)))
|
|
127
|
+
.sort();
|
|
128
|
+
}
|
|
129
|
+
catch {
|
|
130
|
+
return [];
|
|
131
|
+
}
|
|
132
|
+
}
|
|
133
|
+
function hasSkillFile(dir) {
|
|
134
|
+
try {
|
|
135
|
+
return statSync(join(dir, SKILL_FILE)).isFile();
|
|
136
|
+
}
|
|
137
|
+
catch {
|
|
138
|
+
return false;
|
|
139
|
+
}
|
|
140
|
+
}
|
|
141
|
+
function isDirectory(path) {
|
|
142
|
+
try {
|
|
143
|
+
return existsSync(path) && statSync(path).isDirectory();
|
|
144
|
+
}
|
|
145
|
+
catch {
|
|
146
|
+
return false;
|
|
147
|
+
}
|
|
148
|
+
}
|
|
149
|
+
function canonical(path) {
|
|
150
|
+
try {
|
|
151
|
+
return realpathSync(path);
|
|
152
|
+
}
|
|
153
|
+
catch {
|
|
154
|
+
return path;
|
|
155
|
+
}
|
|
156
|
+
}
|
|
157
|
+
//# sourceMappingURL=skills-discovery.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"skills-discovery.js","sourceRoot":"","sources":["../../src/lib/skills-discovery.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,66 @@
|
|
|
1
|
+
import { type SkillSyncResult, type SkillUpload } from './api-client.js';
|
|
2
|
+
import { type DiscoveredSkill, type SkillScope } from './skills-discovery.js';
|
|
3
|
+
/**
|
|
4
|
+
* The "discover, fingerprint, upload what changed" pipeline behind
|
|
5
|
+
* `halyard skills sync` and the session-start hook. Change detection is
|
|
6
|
+
* two-tier: the org-keyed ledger in ~/.halyard/sync-state.json skips
|
|
7
|
+
* unchanged skills with no network at all, and the server compares the
|
|
8
|
+
* fingerprint again for anything the ledger missed (fresh machine, --force).
|
|
9
|
+
*/
|
|
10
|
+
export type SkillScopeSelection = SkillScope | 'all';
|
|
11
|
+
export interface SkillsSyncOptions {
|
|
12
|
+
homeDir: string;
|
|
13
|
+
/** Repository root for project-scope discovery; omit when not in a repo. */
|
|
14
|
+
projectRoot?: string;
|
|
15
|
+
scope: SkillScopeSelection;
|
|
16
|
+
/** Org bucket for the ledger (orgId, or `api-key:<id>`). */
|
|
17
|
+
stateKey: string;
|
|
18
|
+
authHeaders: Record<string, string>;
|
|
19
|
+
apiUrl: string;
|
|
20
|
+
dryRun: boolean;
|
|
21
|
+
/** Ignore the local ledger and let the server decide what changed. */
|
|
22
|
+
force: boolean;
|
|
23
|
+
log: (line: string) => void;
|
|
24
|
+
fetchImpl?: typeof fetch;
|
|
25
|
+
}
|
|
26
|
+
export interface PreparedSkill {
|
|
27
|
+
skill: DiscoveredSkill;
|
|
28
|
+
upload: SkillUpload;
|
|
29
|
+
/** Ledger key: `<scope>:<scopeKey>:<relativePath>`. */
|
|
30
|
+
ledgerKey: string;
|
|
31
|
+
/** Non-fatal problems worth telling the author about. */
|
|
32
|
+
warnings: string[];
|
|
33
|
+
}
|
|
34
|
+
export interface SkillsSyncSummary {
|
|
35
|
+
found: number;
|
|
36
|
+
created: number;
|
|
37
|
+
updated: number;
|
|
38
|
+
unchanged: number;
|
|
39
|
+
/** Skipped by the local ledger (already synced at this fingerprint). */
|
|
40
|
+
skipped: number;
|
|
41
|
+
/** Unreadable locally, rejected by the server, or lost to a request failure. */
|
|
42
|
+
failed: number;
|
|
43
|
+
results: SkillSyncResult[];
|
|
44
|
+
}
|
|
45
|
+
/** Discover every skill in the selected scopes. */
|
|
46
|
+
export declare function discoverSelectedSkills(options: {
|
|
47
|
+
scope: SkillScopeSelection;
|
|
48
|
+
homeDir: string;
|
|
49
|
+
projectRoot?: string;
|
|
50
|
+
}): DiscoveredSkill[];
|
|
51
|
+
/**
|
|
52
|
+
* Identity of a repo for project-scope skills: the normalized origin remote
|
|
53
|
+
* (`github.com/owner/repo`) so the same skill synced from two machines is one
|
|
54
|
+
* entry. A repo with no remote has no shared identity, so it gets a
|
|
55
|
+
* machine-local one — `local:<basename>:<hash of the real path>` — rather
|
|
56
|
+
* than a bare basename that every other remote-less `api` repo would share.
|
|
57
|
+
*/
|
|
58
|
+
export declare function projectScopeKey(projectRoot: string): string;
|
|
59
|
+
/**
|
|
60
|
+
* Read, parse and fingerprint one discovered skill into its upload payload.
|
|
61
|
+
* Throws when the skill cannot be uploaded at all (unreadable, or a body the
|
|
62
|
+
* server would reject); softer problems come back as `warnings`.
|
|
63
|
+
*/
|
|
64
|
+
export declare function prepareSkill(skill: DiscoveredSkill, scopeKey: string): PreparedSkill;
|
|
65
|
+
export declare function runSkillsSync(options: SkillsSyncOptions): Promise<SkillsSyncSummary>;
|
|
66
|
+
//# sourceMappingURL=skills-sync.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"skills-sync.d.ts","sourceRoot":"","sources":["../../src/lib/skills-sync.ts"],"names":[],"mappings":"AAGA,OAAO,EAAc,KAAK,eAAe,EAAE,KAAK,WAAW,EAAE,MAAM,iBAAiB,CAAA;AAMpF,OAAO,EAGL,KAAK,eAAe,EACpB,KAAK,UAAU,EAChB,MAAM,uBAAuB,CAAA;AAS9B;;;;;;GAMG;AAEH,MAAM,MAAM,mBAAmB,GAAG,UAAU,GAAG,KAAK,CAAA;AAEpD,MAAM,WAAW,iBAAiB;IAChC,OAAO,EAAE,MAAM,CAAA;IACf,4EAA4E;IAC5E,WAAW,CAAC,EAAE,MAAM,CAAA;IACpB,KAAK,EAAE,mBAAmB,CAAA;IAC1B,4DAA4D;IAC5D,QAAQ,EAAE,MAAM,CAAA;IAChB,WAAW,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAA;IACnC,MAAM,EAAE,MAAM,CAAA;IACd,MAAM,EAAE,OAAO,CAAA;IACf,sEAAsE;IACtE,KAAK,EAAE,OAAO,CAAA;IACd,GAAG,EAAE,CAAC,IAAI,EAAE,MAAM,KAAK,IAAI,CAAA;IAC3B,SAAS,CAAC,EAAE,OAAO,KAAK,CAAA;CACzB;AAED,MAAM,WAAW,aAAa;IAC5B,KAAK,EAAE,eAAe,CAAA;IACtB,MAAM,EAAE,WAAW,CAAA;IACnB,uDAAuD;IACvD,SAAS,EAAE,MAAM,CAAA;IACjB,yDAAyD;IACzD,QAAQ,EAAE,MAAM,EAAE,CAAA;CACnB;AAED,MAAM,WAAW,iBAAiB;IAChC,KAAK,EAAE,MAAM,CAAA;IACb,OAAO,EAAE,MAAM,CAAA;IACf,OAAO,EAAE,MAAM,CAAA;IACf,SAAS,EAAE,MAAM,CAAA;IACjB,wEAAwE;IACxE,OAAO,EAAE,MAAM,CAAA;IACf,gFAAgF;IAChF,MAAM,EAAE,MAAM,CAAA;IACd,OAAO,EAAE,eAAe,EAAE,CAAA;CAC3B;AAUD,mDAAmD;AACnD,wBAAgB,sBAAsB,CAAC,OAAO,EAAE;IAC9C,KAAK,EAAE,mBAAmB,CAAA;IAC1B,OAAO,EAAE,MAAM,CAAA;IACf,WAAW,CAAC,EAAE,MAAM,CAAA;CACrB,GAAG,eAAe,EAAE,CASpB;AAED;;;;;;GAMG;AACH,wBAAgB,eAAe,CAAC,WAAW,EAAE,MAAM,GAAG,MAAM,CAW3D;AAED;;;;GAIG;AACH,wBAAgB,YAAY,CAAC,KAAK,EAAE,eAAe,EAAE,QAAQ,EAAE,MAAM,GAAG,aAAa,CAsDpF;AAuID,wBAAsB,aAAa,CAAC,OAAO,EAAE,iBAAiB,GAAG,OAAO,CAAC,iBAAiB,CAAC,CAuC1F"}
|