skilld 1.7.4 → 2.0.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/_chunks/add.mjs +66 -0
- package/dist/_chunks/add.mjs.map +1 -0
- package/dist/_chunks/agent-prompt.mjs +88 -0
- package/dist/_chunks/agent-prompt.mjs.map +1 -0
- package/dist/_chunks/agent.mjs +81 -57
- package/dist/_chunks/agent.mjs.map +1 -1
- package/dist/_chunks/args.mjs +42 -0
- package/dist/_chunks/args.mjs.map +1 -0
- package/dist/_chunks/assemble.mjs +10 -7
- package/dist/_chunks/assemble.mjs.map +1 -1
- package/dist/_chunks/author.mjs +33 -17
- package/dist/_chunks/author.mjs.map +1 -1
- package/dist/_chunks/cache.mjs +143 -183
- package/dist/_chunks/cache.mjs.map +1 -1
- package/dist/_chunks/cache2.mjs +7 -6
- package/dist/_chunks/cache2.mjs.map +1 -1
- package/dist/_chunks/client.mjs +117 -0
- package/dist/_chunks/client.mjs.map +1 -0
- package/dist/_chunks/core.mjs +5 -5
- package/dist/_chunks/detect.mjs +53 -43
- package/dist/_chunks/detect.mjs.map +1 -1
- package/dist/_chunks/eject.mjs +69 -0
- package/dist/_chunks/eject.mjs.map +1 -0
- package/dist/_chunks/embedding-cache2.mjs +1 -1
- package/dist/_chunks/env.mjs +19 -0
- package/dist/_chunks/env.mjs.map +1 -0
- package/dist/_chunks/install-many.mjs +376 -0
- package/dist/_chunks/install-many.mjs.map +1 -0
- package/dist/_chunks/install.mjs +81 -326
- package/dist/_chunks/install.mjs.map +1 -1
- package/dist/_chunks/intro.mjs +63 -0
- package/dist/_chunks/intro.mjs.map +1 -0
- package/dist/_chunks/list.mjs +2 -2
- package/dist/_chunks/list.mjs.map +1 -1
- package/dist/_chunks/lockfile.mjs +3 -2
- package/dist/_chunks/lockfile.mjs.map +1 -1
- package/dist/_chunks/login.mjs +233 -0
- package/dist/_chunks/login.mjs.map +1 -0
- package/dist/_chunks/logout.mjs +27 -0
- package/dist/_chunks/logout.mjs.map +1 -0
- package/dist/_chunks/map.mjs +11 -0
- package/dist/_chunks/map.mjs.map +1 -0
- package/dist/_chunks/markdown.mjs +79 -54
- package/dist/_chunks/markdown.mjs.map +1 -1
- package/dist/_chunks/menu.mjs +33 -0
- package/dist/_chunks/menu.mjs.map +1 -0
- package/dist/_chunks/model-picker.mjs +61 -0
- package/dist/_chunks/model-picker.mjs.map +1 -0
- package/dist/_chunks/monorepo.mjs +4 -2
- package/dist/_chunks/monorepo.mjs.map +1 -1
- package/dist/_chunks/package-json.mjs.map +1 -1
- package/dist/_chunks/paths.mjs +3 -5
- package/dist/_chunks/paths.mjs.map +1 -1
- package/dist/_chunks/{sync-pipeline.mjs → pipeline.mjs} +346 -313
- package/dist/_chunks/pipeline.mjs.map +1 -0
- package/dist/_chunks/pool2.mjs +1 -1
- package/dist/_chunks/portable.mjs +151 -0
- package/dist/_chunks/portable.mjs.map +1 -0
- package/dist/_chunks/prepare-hook.mjs +2 -0
- package/dist/_chunks/prepare-hook2.mjs +61 -0
- package/dist/_chunks/prepare-hook2.mjs.map +1 -0
- package/dist/_chunks/prepare.mjs +47 -3
- package/dist/_chunks/prepare.mjs.map +1 -1
- package/dist/_chunks/prepare2.mjs +7 -6
- package/dist/_chunks/prepare2.mjs.map +1 -1
- package/dist/_chunks/prompts.mjs +484 -74
- package/dist/_chunks/prompts.mjs.map +1 -1
- package/dist/_chunks/pull.mjs +219 -0
- package/dist/_chunks/pull.mjs.map +1 -0
- package/dist/_chunks/regex.mjs +19 -0
- package/dist/_chunks/regex.mjs.map +1 -0
- package/dist/_chunks/retriv.mjs +2 -171
- package/dist/_chunks/retriv2.mjs +159 -0
- package/dist/_chunks/retriv2.mjs.map +1 -0
- package/dist/_chunks/sanitize.mjs +12 -9
- package/dist/_chunks/sanitize.mjs.map +1 -1
- package/dist/_chunks/search-helpers.mjs +8 -6
- package/dist/_chunks/search-helpers.mjs.map +1 -1
- package/dist/_chunks/search-interactive.mjs +23 -20
- package/dist/_chunks/search-interactive.mjs.map +1 -1
- package/dist/_chunks/search.mjs +3 -3
- package/dist/_chunks/search.mjs.map +1 -1
- package/dist/_chunks/semver.mjs +2755 -1
- package/dist/_chunks/semver.mjs.map +1 -1
- package/dist/_chunks/skill-installer2.mjs +10 -11
- package/dist/_chunks/skill-installer2.mjs.map +1 -1
- package/dist/_chunks/skills.mjs +6 -7
- package/dist/_chunks/skills.mjs.map +1 -1
- package/dist/_chunks/store.mjs +107 -0
- package/dist/_chunks/store.mjs.map +1 -0
- package/dist/_chunks/sync.mjs +411 -910
- package/dist/_chunks/sync.mjs.map +1 -1
- package/dist/_chunks/sync2.mjs +2 -5
- package/dist/_chunks/telemetry.mjs +26 -0
- package/dist/_chunks/telemetry.mjs.map +1 -0
- package/dist/_chunks/uninstall.mjs +12 -9
- package/dist/_chunks/uninstall.mjs.map +1 -1
- package/dist/_chunks/update.mjs +171 -0
- package/dist/_chunks/update.mjs.map +1 -0
- package/dist/_chunks/upload.mjs +3 -3
- package/dist/_chunks/validate.mjs +1 -1
- package/dist/_chunks/version.mjs +16 -17
- package/dist/_chunks/version.mjs.map +1 -1
- package/dist/_chunks/whoami.mjs +21 -0
- package/dist/_chunks/whoami.mjs.map +1 -0
- package/dist/_chunks/wizard.mjs +2 -190
- package/dist/_chunks/wizard2.mjs +200 -0
- package/dist/_chunks/wizard2.mjs.map +1 -0
- package/dist/cli.mjs +72 -53
- package/dist/cli.mjs.map +1 -1
- package/dist/prepare.mjs +4 -3
- package/dist/prepare.mjs.map +1 -1
- package/dist/retriv/worker.d.mts +5 -1
- package/dist/retriv/worker.d.mts.map +1 -1
- package/dist/retriv/worker.mjs +1 -1
- package/package.json +19 -28
- package/dist/_chunks/author-group.mjs +0 -17
- package/dist/_chunks/author-group.mjs.map +0 -1
- package/dist/_chunks/cli-helpers.mjs +0 -335
- package/dist/_chunks/cli-helpers.mjs.map +0 -1
- package/dist/_chunks/cli-helpers2.mjs +0 -2
- package/dist/_chunks/index.d.mts +0 -344
- package/dist/_chunks/index.d.mts.map +0 -1
- package/dist/_chunks/index2.d.mts +0 -279
- package/dist/_chunks/index2.d.mts.map +0 -1
- package/dist/_chunks/index3.d.mts +0 -44
- package/dist/_chunks/index3.d.mts.map +0 -1
- package/dist/_chunks/index4.d.mts +0 -553
- package/dist/_chunks/index4.d.mts.map +0 -1
- package/dist/_chunks/package-registry.mjs +0 -465
- package/dist/_chunks/package-registry.mjs.map +0 -1
- package/dist/_chunks/retriv.mjs.map +0 -1
- package/dist/_chunks/setup.mjs +0 -17
- package/dist/_chunks/setup.mjs.map +0 -1
- package/dist/_chunks/sources.mjs +0 -2654
- package/dist/_chunks/sources.mjs.map +0 -1
- package/dist/_chunks/sync-pipeline.mjs.map +0 -1
- package/dist/_chunks/sync-registry.mjs +0 -65
- package/dist/_chunks/sync-registry.mjs.map +0 -1
- package/dist/_chunks/types.d.mts +0 -76
- package/dist/_chunks/types.d.mts.map +0 -1
- package/dist/_chunks/types2.d.mts +0 -88
- package/dist/_chunks/types2.d.mts.map +0 -1
- package/dist/_chunks/wizard.mjs.map +0 -1
- package/dist/agent/index.d.mts +0 -2
- package/dist/agent/index.mjs +0 -4
- package/dist/cache/index.d.mts +0 -2
- package/dist/cache/index.mjs +0 -5
- package/dist/index.d.mts +0 -6
- package/dist/index.mjs +0 -6
- package/dist/retriv/index.d.mts +0 -3
- package/dist/retriv/index.mjs +0 -2
- package/dist/sources/index.d.mts +0 -3
- package/dist/sources/index.mjs +0 -3
- package/dist/types.d.mts +0 -4
- package/dist/types.mjs +0 -1
|
@@ -1,76 +1,101 @@
|
|
|
1
1
|
import { n as yamlParseKV } from "./yaml.mjs";
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
};
|
|
2
|
+
const FRONTMATTER_RE = /^---\r?\n([\s\S]*?)\r?\n---\r?\n?/;
|
|
3
|
+
const HEADING_LINE_RE = /^(#{1,6})[ \t]+([^ \t\r\n][^\r\n]*)$/gm;
|
|
4
|
+
const ANCHOR_RE = /\s*\{#[^}]+\}\s*$/;
|
|
5
|
+
const BACKSLASH_PREFIX_RE = /^\\+\s*/;
|
|
6
|
+
const INLINE_CODE_RE = /`([^`]+)`/g;
|
|
7
|
+
const LINK_RE = /(?<!!)\[([^\]]+)\]\(([^)\s]+)(?:\s+"[^"]*")?\)/g;
|
|
8
|
+
const HEADING_START_RE = /^#{1,6}\s/;
|
|
9
|
+
const BLOCKQUOTE_START_RE = /^>\s?/;
|
|
10
|
+
const LIST_ITEM_START_RE = /^[-*+]\s/;
|
|
11
|
+
const ORDERED_LIST_ITEM_START_RE = /^\d+\.\s/;
|
|
12
|
+
const TABLE_ROW_START_RE = /^\|/;
|
|
13
|
+
const INDENTED_CODE_START_RE = /^ {4}/;
|
|
14
|
+
const FENCE_START_RE = /^\s*```/;
|
|
15
|
+
const MARKDOWN_LINK_RE = /\[([^\]]+)\]\([^)]+\)/g;
|
|
16
|
+
const MARKDOWN_FORMATTING_RE = /[`*_~]/g;
|
|
17
|
+
const FENCED_CODE_BLOCK_RE = /```[\s\S]*?```/g;
|
|
18
|
+
const INLINE_CODE_SPAN_RE = /`[^`\n]*`/g;
|
|
19
|
+
function stripFrontmatter(content) {
|
|
20
|
+
const m = content.match(FRONTMATTER_RE);
|
|
21
|
+
return m ? content.slice(m[0].length).trim() : content;
|
|
23
22
|
}
|
|
24
23
|
function parseFrontmatter(content) {
|
|
25
|
-
|
|
24
|
+
const m = content.match(FRONTMATTER_RE);
|
|
25
|
+
if (!m) return {};
|
|
26
|
+
const fm = {};
|
|
27
|
+
for (const line of m[1].split("\n")) {
|
|
28
|
+
const kv = yamlParseKV(line);
|
|
29
|
+
if (kv) fm[kv[0]] = kv[1];
|
|
30
|
+
}
|
|
31
|
+
return fm;
|
|
26
32
|
}
|
|
27
|
-
function
|
|
28
|
-
return
|
|
33
|
+
function cleanHeadingText(raw) {
|
|
34
|
+
return raw.replace(ANCHOR_RE, "").replace(BACKSLASH_PREFIX_RE, "").replace(INLINE_CODE_RE, "$1").trim();
|
|
29
35
|
}
|
|
30
36
|
function extractTitle(content) {
|
|
31
|
-
const
|
|
37
|
+
const fm = parseFrontmatter(content);
|
|
32
38
|
if (fm.title) return fm.title;
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
39
|
+
const body = stripFrontmatter(content);
|
|
40
|
+
for (const m of body.matchAll(HEADING_LINE_RE)) if (m[1] === "#") {
|
|
41
|
+
const text = cleanHeadingText(m[2]);
|
|
42
|
+
if (text) return text;
|
|
43
|
+
}
|
|
44
|
+
return null;
|
|
45
|
+
}
|
|
46
|
+
function isBlockStarter(trimmed, raw) {
|
|
47
|
+
return HEADING_START_RE.test(trimmed) || BLOCKQUOTE_START_RE.test(trimmed) || LIST_ITEM_START_RE.test(trimmed) || ORDERED_LIST_ITEM_START_RE.test(trimmed) || TABLE_ROW_START_RE.test(trimmed) || trimmed.startsWith("<") || INDENTED_CODE_START_RE.test(raw);
|
|
41
48
|
}
|
|
42
49
|
function extractDescription(content) {
|
|
43
|
-
const
|
|
44
|
-
let
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
const
|
|
48
|
-
if (
|
|
49
|
-
|
|
50
|
+
const lines = stripFrontmatter(content).split("\n");
|
|
51
|
+
let inFence = false;
|
|
52
|
+
let inHtml = false;
|
|
53
|
+
for (let i = 0; i < lines.length; i++) {
|
|
54
|
+
const line = lines[i];
|
|
55
|
+
if (FENCE_START_RE.test(line)) {
|
|
56
|
+
inFence = !inFence;
|
|
57
|
+
continue;
|
|
58
|
+
}
|
|
59
|
+
if (inFence) continue;
|
|
60
|
+
const trimmed = line.trim();
|
|
61
|
+
if (inHtml) {
|
|
62
|
+
if (!trimmed) inHtml = false;
|
|
63
|
+
continue;
|
|
64
|
+
}
|
|
65
|
+
if (trimmed.startsWith("<")) {
|
|
66
|
+
inHtml = true;
|
|
67
|
+
continue;
|
|
68
|
+
}
|
|
69
|
+
if (!trimmed || isBlockStarter(trimmed, line)) continue;
|
|
70
|
+
let para = trimmed;
|
|
71
|
+
for (let j = i + 1; j < lines.length; j++) {
|
|
72
|
+
const next = lines[j];
|
|
73
|
+
const nextTrim = next.trim();
|
|
74
|
+
if (!nextTrim || isBlockStarter(nextTrim, next)) break;
|
|
75
|
+
para += ` ${nextTrim}`;
|
|
76
|
+
}
|
|
77
|
+
let clean = para.replace(MARKDOWN_LINK_RE, "$1").replace(MARKDOWN_FORMATTING_RE, "");
|
|
50
78
|
if (clean.length > 150) clean = `${clean.slice(0, 147)}...`;
|
|
51
|
-
|
|
52
|
-
}
|
|
53
|
-
return
|
|
79
|
+
return clean;
|
|
80
|
+
}
|
|
81
|
+
return null;
|
|
54
82
|
}
|
|
55
83
|
function extractLinks(content) {
|
|
56
|
-
const
|
|
84
|
+
const sanitized = stripFrontmatter(content).replace(FENCED_CODE_BLOCK_RE, "").replace(INLINE_CODE_SPAN_RE, "");
|
|
57
85
|
const links = [];
|
|
58
86
|
const seen = /* @__PURE__ */ new Set();
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
87
|
+
for (const m of sanitized.matchAll(LINK_RE)) {
|
|
88
|
+
const url = m[2];
|
|
89
|
+
if (!seen.has(url)) {
|
|
90
|
+
seen.add(url);
|
|
62
91
|
links.push({
|
|
63
|
-
title:
|
|
64
|
-
url
|
|
92
|
+
title: m[1],
|
|
93
|
+
url
|
|
65
94
|
});
|
|
66
95
|
}
|
|
67
|
-
}
|
|
96
|
+
}
|
|
68
97
|
return links;
|
|
69
98
|
}
|
|
70
|
-
function stripFrontmatter(content) {
|
|
71
|
-
const match = content.match(/^---\r?\n[\s\S]*?\r?\n---\r?\n/);
|
|
72
|
-
return match ? content.slice(match[0].length).trim() : content;
|
|
73
|
-
}
|
|
74
99
|
export { stripFrontmatter as a, parseFrontmatter as i, extractLinks as n, extractTitle as r, extractDescription as t };
|
|
75
100
|
|
|
76
101
|
//# sourceMappingURL=markdown.mjs.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"markdown.mjs","names":[],"sources":["../../src/core/markdown.ts"],"sourcesContent":["/**\n *
|
|
1
|
+
{"version":3,"file":"markdown.mjs","names":[],"sources":["../../src/core/markdown.ts"],"sourcesContent":["/**\n * Lightweight regex-based markdown utilities.\n * Operations needed (frontmatter, title, description, links, headings) are\n * simple enough that a full AST stack would be overkill.\n */\n\nimport { yamlParseKV } from './yaml.ts'\n\nexport interface MdLink {\n title: string\n url: string\n}\n\nexport interface Heading {\n depth: number\n text: string\n}\n\nconst FRONTMATTER_RE = /^---\\r?\\n([\\s\\S]*?)\\r?\\n---\\r?\\n?/\nconst HEADING_LINE_RE = /^(#{1,6})[ \\t]+([^ \\t\\r\\n][^\\r\\n]*)$/gm\nconst ANCHOR_RE = /\\s*\\{#[^}]+\\}\\s*$/\nconst BACKSLASH_PREFIX_RE = /^\\\\+\\s*/\nconst INLINE_CODE_RE = /`([^`]+)`/g\nconst LINK_RE = /(?<!!)\\[([^\\]]+)\\]\\(([^)\\s]+)(?:\\s+\"[^\"]*\")?\\)/g\nconst HEADING_START_RE = /^#{1,6}\\s/\nconst BLOCKQUOTE_START_RE = /^>\\s?/\nconst LIST_ITEM_START_RE = /^[-*+]\\s/\nconst ORDERED_LIST_ITEM_START_RE = /^\\d+\\.\\s/\nconst TABLE_ROW_START_RE = /^\\|/\nconst INDENTED_CODE_START_RE = /^ {4}/\nconst FENCE_START_RE = /^\\s*```/\nconst MARKDOWN_LINK_RE = /\\[([^\\]]+)\\]\\([^)]+\\)/g\nconst MARKDOWN_FORMATTING_RE = /[`*_~]/g\nconst FENCED_CODE_BLOCK_RE = /```[\\s\\S]*?```/g\nconst INLINE_CODE_SPAN_RE = /`[^`\\n]*`/g\n\n/** Strip frontmatter block, return body only. */\nexport function stripFrontmatter(content: string): string {\n const m = content.match(FRONTMATTER_RE)\n return m ? content.slice(m[0].length).trim() : content\n}\n\n/** Extract frontmatter key-value pairs. */\nexport function parseFrontmatter(content: string): Record<string, string> {\n const m = content.match(FRONTMATTER_RE)\n if (!m)\n return {}\n const fm: Record<string, string> = {}\n for (const line of m[1]!.split('\\n')) {\n const kv = yamlParseKV(line)\n if (kv)\n fm[kv[0]] = kv[1]\n }\n return fm\n}\n\nfunction cleanHeadingText(raw: string): string {\n return raw\n .replace(ANCHOR_RE, '')\n .replace(BACKSLASH_PREFIX_RE, '')\n .replace(INLINE_CODE_RE, '$1')\n .trim()\n}\n\n/** Extract all headings in document order. */\nexport function extractHeadings(content: string): Heading[] {\n const body = stripFrontmatter(content)\n const headings: Heading[] = []\n for (const m of body.matchAll(HEADING_LINE_RE)) {\n const text = cleanHeadingText(m[2]!)\n if (text)\n headings.push({ depth: m[1]!.length, text })\n }\n return headings\n}\n\n/** Extract title: frontmatter title > first h1 > null. */\nexport function extractTitle(content: string): string | null {\n const fm = parseFrontmatter(content)\n if (fm.title)\n return fm.title\n const body = stripFrontmatter(content)\n for (const m of body.matchAll(HEADING_LINE_RE)) {\n if (m[1] === '#') {\n const text = cleanHeadingText(m[2]!)\n if (text)\n return text\n }\n }\n return null\n}\n\nfunction isBlockStarter(trimmed: string, raw: string): boolean {\n return HEADING_START_RE.test(trimmed)\n || BLOCKQUOTE_START_RE.test(trimmed)\n || LIST_ITEM_START_RE.test(trimmed)\n || ORDERED_LIST_ITEM_START_RE.test(trimmed)\n || TABLE_ROW_START_RE.test(trimmed)\n || trimmed.startsWith('<')\n || INDENTED_CODE_START_RE.test(raw)\n}\n\n/** Extract first top-level paragraph, stripped of formatting, max 150 chars. */\nexport function extractDescription(content: string): string | null {\n const body = stripFrontmatter(content)\n const lines = body.split('\\n')\n let inFence = false\n let inHtml = false\n\n for (let i = 0; i < lines.length; i++) {\n const line = lines[i]!\n if (FENCE_START_RE.test(line)) {\n inFence = !inFence\n continue\n }\n if (inFence)\n continue\n\n const trimmed = line.trim()\n\n if (inHtml) {\n if (!trimmed)\n inHtml = false\n continue\n }\n if (trimmed.startsWith('<')) {\n inHtml = true\n continue\n }\n\n if (!trimmed || isBlockStarter(trimmed, line))\n continue\n\n let para = trimmed\n for (let j = i + 1; j < lines.length; j++) {\n const next = lines[j]!\n const nextTrim = next.trim()\n if (!nextTrim || isBlockStarter(nextTrim, next))\n break\n para += ` ${nextTrim}`\n }\n\n let clean = para.replace(MARKDOWN_LINK_RE, '$1').replace(MARKDOWN_FORMATTING_RE, '')\n if (clean.length > 150)\n clean = `${clean.slice(0, 147)}...`\n return clean\n }\n\n return null\n}\n\n/** Extract all links (deduped by url), excluding images and links in code. */\nexport function extractLinks(content: string): MdLink[] {\n const body = stripFrontmatter(content)\n const sanitized = body\n .replace(FENCED_CODE_BLOCK_RE, '')\n .replace(INLINE_CODE_SPAN_RE, '')\n\n const links: MdLink[] = []\n const seen = new Set<string>()\n for (const m of sanitized.matchAll(LINK_RE)) {\n const url = m[2]!\n if (!seen.has(url)) {\n seen.add(url)\n links.push({ title: m[1]!, url })\n }\n }\n return links\n}\n"],"mappings":";;;;;AAkBA,MAAM,iBAAiB;AACvB,MAAM,UAAA;AACN,MAAM,mBAAY;AAClB,MAAM,sBAAsB;AAC5B,MAAM,qBAAiB;AACvB,MAAM,6BAAU;AAChB,MAAM,qBAAmB;AACzB,MAAM,yBAAsB;AAC5B,MAAM,iBAAA;AACN,MAAM,mBAAA;AACN,MAAM,yBAAqB;AAC3B,MAAM,uBAAA;AACN,MAAM,sBAAiB;AAEvB,SAAM,iBAAA,SAAyB;CAC/B,MAAM,IAAA,QAAA,MAAA,eAAuB;CAC7B,OAAM,IAAA,QAAA,MAAA,EAAsB,GAAA,OAAA,CAAA,MAAA,GAAA;;SAIpB,iBAAkB,SAAA;CACxB,MAAA,IAAO,QAAI,MAAQ,eAAmB;;;CAIxC,KAAA,MAAgB,QAAA,EAAA,GAAA,MAAiB,KAAyC,EAAA;EACxE,MAAM,KAAI,YAAc,KAAA;EACxB,IAAK,IACH,GAAA,GAAO,MAAE,GAAA;;CAEX,OAAK;;SAEC,iBACa,KAAA;;;AAKrB,SAAS,aAAA,SAAsC;CAC7C,MAAA,KACG,iBAAQ,QACR;;;CAkBL,KAAA,MAAgB,KAAA,KAAa,SAAgC,gBAAA,EAAA,IAAA,EAAA,OAAA,KAAA;EAC3D,MAAM,OAAK,iBAAiB,EAAA,GAAQ;EACpC,IAAI,MAAG,OACL;;CAEF,OAAK;;SAGG,eACK,SAAA,KAAA;;;AAMf,SAAS,mBAAe,SAAiB;CACvC,MAAA,QAAO,iBAAsB,QAAQ,CAAA,MAChC,KAAA;;;CASP,KAAA,IAAgB,IAAA,GAAA,IAAA,MAAA,QAAmB,KAAgC;EAEjE,MAAM,OADO,MAAA;EAEb,IAAI,eAAU,KAAA,KAAA,EAAA;GACd,UAAI,CAAS;GAEb;;EAEE,IAAI,SAAA;QACF,UAAW,KAAA,MAAA;MACX,QAAA;;GAEF;;EAKA,IAAI,QAAQ,WAAA,IAAA,EAAA;GACV,SAAK;GAEL;;EAEF,IAAI,CAAA,WAAQ,eAAiB,SAAA,KAAA,EAAA;MAC3B,OAAS;OACT,IAAA,IAAA,IAAA,GAAA,IAAA,MAAA,QAAA,KAAA;;GAGF,MAAK,WAAW,KAAA,MAAA;GAGhB,IAAI,CAAA,YAAO,eAAA,UAAA,KAAA,EAAA;GACX,QAAS,IAAI;;MAEX,QAAM,KAAA,QAAgB,kBAAM,KAAA,CAAA,QAAA,wBAAA,GAAA;MAC5B,MAAK,SAAY,KAAA,QAAA,GAAe,MAAA,MAAU,GACxC,IAAA,CAAA;SACF;;QAGE;;;CAMN,MAAA,YAAO,iBAAA,QAAA,CAAA,QAAA,sBAAA,GAAA,CAAA,QAAA,qBAAA,GAAA;;;CAIT,KAAA,MAAgB,KAAA,UAAa,SAA2B,QAAA,EAAA;EAEtD,MAAM,MAAA,EAAA;EAIN,IAAA,CAAM,KAAA,IAAkB,IAAE,EAAA;GAC1B,KAAM,IAAA,IAAA;GACN,MAAK,KAAM;IACT,OAAM,EAAA;IACN;IACE,CAAA;;;QAC2B"}
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
import * as p from "@clack/prompts";
|
|
2
|
+
var MenuCancel = class extends Error {
|
|
3
|
+
name = "MenuCancel";
|
|
4
|
+
};
|
|
5
|
+
function guard(value) {
|
|
6
|
+
if (p.isCancel(value)) throw new MenuCancel();
|
|
7
|
+
return value;
|
|
8
|
+
}
|
|
9
|
+
async function menuLoop(opts) {
|
|
10
|
+
while (true) {
|
|
11
|
+
const options = await opts.options();
|
|
12
|
+
const initial = typeof opts.initialValue === "function" ? opts.initialValue() : opts.initialValue;
|
|
13
|
+
const choice = opts.searchable ? await p.autocomplete({
|
|
14
|
+
message: opts.message,
|
|
15
|
+
options,
|
|
16
|
+
...initial != null ? { initialValue: initial } : {}
|
|
17
|
+
}) : await p.select({
|
|
18
|
+
message: opts.message,
|
|
19
|
+
options,
|
|
20
|
+
...initial != null ? { initialValue: initial } : {}
|
|
21
|
+
});
|
|
22
|
+
if (p.isCancel(choice)) return;
|
|
23
|
+
try {
|
|
24
|
+
if (await opts.onSelect(choice)) return;
|
|
25
|
+
} catch (err) {
|
|
26
|
+
if (err instanceof MenuCancel) continue;
|
|
27
|
+
throw err;
|
|
28
|
+
}
|
|
29
|
+
}
|
|
30
|
+
}
|
|
31
|
+
export { menuLoop as n, guard as t };
|
|
32
|
+
|
|
33
|
+
//# sourceMappingURL=menu.mjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"menu.mjs","names":[],"sources":["../../src/cli/menu.ts"],"sourcesContent":["import * as p from '@clack/prompts'\n\nexport class MenuCancel extends Error { override name = 'MenuCancel' }\n\nexport function guard<T>(value: T | symbol): T {\n if (p.isCancel(value))\n throw new MenuCancel()\n return value as T\n}\n\nexport interface MenuOption {\n label: string\n value: string\n hint?: string\n}\n\nexport async function menuLoop(opts: {\n message: string\n options: () => MenuOption[] | Promise<MenuOption[]>\n onSelect: (value: string) => Promise<boolean | void>\n initialValue?: string | (() => string | undefined)\n searchable?: boolean\n}): Promise<void> {\n while (true) {\n const options = await opts.options()\n const initial = typeof opts.initialValue === 'function' ? opts.initialValue() : opts.initialValue\n const choice = opts.searchable\n ? await p.autocomplete({ message: opts.message, options, ...(initial != null ? { initialValue: initial } : {}) })\n : await p.select({ message: opts.message, options, ...(initial != null ? { initialValue: initial } : {}) })\n if (p.isCancel(choice))\n return\n try {\n if (await opts.onSelect(choice as string))\n return\n }\n catch (err) {\n if (err instanceof MenuCancel)\n continue\n throw err\n }\n }\n}\n"],"mappings":";AAEA,IAAa,aAAb,cAAgC,MAAM;CAAE,OAAgB;;AAExD,SAAgB,MAAS,OAAsB;CAC7C,IAAI,EAAE,SAAS,MAAM,EACnB,MAAM,IAAI,YAAY;CACxB,OAAO;;AAST,eAAsB,SAAS,MAMb;CAChB,OAAO,MAAM;EACX,MAAM,UAAU,MAAM,KAAK,SAAS;EACpC,MAAM,UAAU,OAAO,KAAK,iBAAiB,aAAa,KAAK,cAAc,GAAG,KAAK;EACrF,MAAM,SAAS,KAAK,aAChB,MAAM,EAAE,aAAa;GAAE,SAAS,KAAK;GAAS;GAAS,GAAI,WAAW,OAAO,EAAE,cAAc,SAAS,GAAG,EAAE;GAAG,CAAC,GAC/G,MAAM,EAAE,OAAO;GAAE,SAAS,KAAK;GAAS;GAAS,GAAI,WAAW,OAAO,EAAE,cAAc,SAAS,GAAG,EAAE;GAAG,CAAC;EAC7G,IAAI,EAAE,SAAS,OAAO,EACpB;EACF,IAAI;GACF,IAAI,MAAM,KAAK,SAAS,OAAiB,EACvC;WAEG,KAAK;GACV,IAAI,eAAe,YACjB;GACF,MAAM"}
|
|
@@ -0,0 +1,61 @@
|
|
|
1
|
+
import { styleText } from "node:util";
|
|
2
|
+
import * as p from "@clack/prompts";
|
|
3
|
+
const OAUTH_NOTE = `${styleText("yellow", "⚠")} OAuth providers are disabled.\n\nConsumer subscription OAuth impersonates official CLI clients and\nviolates provider Terms of Service, risking account bans.\n\nUse API keys or native CLI tools instead:\n ${styleText("cyan", "ANTHROPIC_API_KEY")} / ${styleText("cyan", "claude")} CLI\n ${styleText("cyan", "OPENAI_API_KEY")} / ${styleText("cyan", "codex")} CLI\n ${styleText("cyan", "GEMINI_API_KEY")} / ${styleText("cyan", "gemini")} CLI`;
|
|
4
|
+
const NO_MODELS_MESSAGE = `No enhancement models detected.\n ${styleText("gray", "Skills work fine without this, you get raw docs, issues, and types.\n Enhancement compresses them into a concise cheat sheet with gotchas.")}\n\n To connect a model (optional):\n 1. Set an env var: ANTHROPIC_API_KEY, GEMINI_API_KEY, or OPENAI_API_KEY\n 2. Install a CLI tool: ${styleText("cyan", "claude")}, ${styleText("cyan", "gemini")}, or ${styleText("cyan", "codex")} (restart wizard after)`;
|
|
5
|
+
function groupModelsByProvider(models) {
|
|
6
|
+
const byVendor = /* @__PURE__ */ new Map();
|
|
7
|
+
for (const m of models) {
|
|
8
|
+
const key = m.vendorGroup ?? m.provider;
|
|
9
|
+
if (!byVendor.has(key)) byVendor.set(key, {
|
|
10
|
+
name: key,
|
|
11
|
+
models: []
|
|
12
|
+
});
|
|
13
|
+
byVendor.get(key).models.push(m);
|
|
14
|
+
}
|
|
15
|
+
return byVendor;
|
|
16
|
+
}
|
|
17
|
+
async function pickModel(models, opts = {}) {
|
|
18
|
+
const byProvider = groupModelsByProvider(models);
|
|
19
|
+
const before = opts.before ?? [];
|
|
20
|
+
const after = opts.after ?? [];
|
|
21
|
+
if (byProvider.size === 1 && before.length === 0) {
|
|
22
|
+
const [, group] = [...byProvider.entries()][0];
|
|
23
|
+
const choice = await p.select({
|
|
24
|
+
message: `${group.name}`,
|
|
25
|
+
options: [...group.models.map((m) => ({
|
|
26
|
+
label: m.recommended ? `${m.name} (recommended - fast and cheap)` : m.name,
|
|
27
|
+
value: m.id,
|
|
28
|
+
hint: m.hint
|
|
29
|
+
})), ...after]
|
|
30
|
+
});
|
|
31
|
+
return p.isCancel(choice) ? null : choice;
|
|
32
|
+
}
|
|
33
|
+
const providerChoice = await p.select({
|
|
34
|
+
message: "Select provider",
|
|
35
|
+
options: [
|
|
36
|
+
...before,
|
|
37
|
+
...Array.from(byProvider.entries(), ([key, { name, models: ms }]) => ({
|
|
38
|
+
label: name,
|
|
39
|
+
value: key,
|
|
40
|
+
hint: `${ms.length} models`
|
|
41
|
+
})),
|
|
42
|
+
...after
|
|
43
|
+
]
|
|
44
|
+
});
|
|
45
|
+
if (p.isCancel(providerChoice)) return null;
|
|
46
|
+
const providerStr = providerChoice;
|
|
47
|
+
if (before.some((o) => o.value === providerStr) || after.some((o) => o.value === providerStr)) return providerStr;
|
|
48
|
+
const group = byProvider.get(providerStr);
|
|
49
|
+
const modelChoice = await p.select({
|
|
50
|
+
message: `Select model (${group.name})`,
|
|
51
|
+
options: group.models.map((m) => ({
|
|
52
|
+
label: m.recommended ? `${m.name} (recommended - fast and cheap)` : m.name,
|
|
53
|
+
value: m.id,
|
|
54
|
+
hint: m.hint
|
|
55
|
+
}))
|
|
56
|
+
});
|
|
57
|
+
return p.isCancel(modelChoice) ? null : modelChoice;
|
|
58
|
+
}
|
|
59
|
+
export { OAUTH_NOTE as n, pickModel as r, NO_MODELS_MESSAGE as t };
|
|
60
|
+
|
|
61
|
+
//# sourceMappingURL=model-picker.mjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"model-picker.mjs","names":[],"sources":["../../src/cli/model-picker.ts"],"sourcesContent":["import { styleText } from 'node:util'\nimport * as p from '@clack/prompts'\n\nexport const OAUTH_NOTE\n = `${styleText('yellow', '⚠')} OAuth providers are disabled.\\n`\n + `\\n`\n + `Consumer subscription OAuth impersonates official CLI clients and\\n`\n + `violates provider Terms of Service, risking account bans.\\n`\n + `\\n`\n + `Use API keys or native CLI tools instead:\\n`\n + ` ${styleText('cyan', 'ANTHROPIC_API_KEY')} / ${styleText('cyan', 'claude')} CLI\\n`\n + ` ${styleText('cyan', 'OPENAI_API_KEY')} / ${styleText('cyan', 'codex')} CLI\\n`\n + ` ${styleText('cyan', 'GEMINI_API_KEY')} / ${styleText('cyan', 'gemini')} CLI`\n\nexport const NO_MODELS_MESSAGE = `No enhancement models detected.\\n`\n + ` ${styleText('gray', 'Skills work fine without this, you get raw docs, issues, and types.\\n Enhancement compresses them into a concise cheat sheet with gotchas.')}\\n`\n + `\\n`\n + ` To connect a model (optional):\\n`\n + ` 1. Set an env var: ANTHROPIC_API_KEY, GEMINI_API_KEY, or OPENAI_API_KEY\\n`\n + ` 2. Install a CLI tool: ${styleText('cyan', 'claude')}, ${styleText('cyan', 'gemini')}, or ${styleText('cyan', 'codex')} (restart wizard after)`\n\nexport function groupModelsByProvider<T extends { provider: string, providerName: string, vendorGroup?: string }>(models: T[]): Map<string, { name: string, models: T[] }> {\n const byVendor = new Map<string, { name: string, models: T[] }>()\n for (const m of models) {\n const key = m.vendorGroup ?? m.provider\n if (!byVendor.has(key))\n byVendor.set(key, { name: key, models: [] })\n byVendor.get(key)!.models.push(m)\n }\n return byVendor\n}\n\nexport interface ModelPickerOptions {\n before?: Array<{ label: string, value: string, hint?: string }>\n after?: Array<{ label: string, value: string, hint?: string }>\n}\n\nexport async function pickModel<T extends { provider: string, providerName: string, name: string, id: string, hint: string, recommended?: boolean }>(\n models: T[],\n opts: ModelPickerOptions = {},\n): Promise<string | null> {\n const byProvider = groupModelsByProvider(models)\n const before = opts.before ?? []\n const after = opts.after ?? []\n\n if (byProvider.size === 1 && before.length === 0) {\n const [, group] = [...byProvider.entries()][0]!\n const choice = await p.select({\n message: `${group.name}`,\n options: [\n ...group.models.map(m => ({\n label: m.recommended ? `${m.name} (recommended - fast and cheap)` : m.name,\n value: m.id,\n hint: m.hint,\n })),\n ...after,\n ],\n })\n return p.isCancel(choice) ? null : choice as string\n }\n\n const providerChoice = await p.select({\n message: 'Select provider',\n options: [\n ...before,\n ...Array.from(byProvider.entries(), ([key, { name, models: ms }]) => ({\n label: name,\n value: key,\n hint: `${ms.length} models`,\n })),\n ...after,\n ],\n })\n\n if (p.isCancel(providerChoice))\n return null\n\n const providerStr = providerChoice as string\n if (before.some(o => o.value === providerStr) || after.some(o => o.value === providerStr))\n return providerStr\n\n const group = byProvider.get(providerStr)!\n const modelChoice = await p.select({\n message: `Select model (${group.name})`,\n options: group.models.map(m => ({\n label: m.recommended ? `${m.name} (recommended - fast and cheap)` : m.name,\n value: m.id,\n hint: m.hint,\n })),\n })\n\n return p.isCancel(modelChoice) ? null : modelChoice as string\n}\n"],"mappings":";;AAGA,MAAa,aACT,GAAG,UAAU,UAAU,IAAI,CAAC,kNAMrB,UAAU,QAAQ,oBAAoB,CAAC,KAAK,UAAU,QAAQ,SAAS,CAAC,UACxE,UAAU,QAAQ,iBAAiB,CAAC,OAAO,UAAU,QAAQ,QAAQ,CAAC,UACtE,UAAU,QAAQ,iBAAiB,CAAC,OAAO,UAAU,QAAQ,SAAS,CAAC;AAElF,MAAa,oBAAoB,sCACxB,UAAU,QAAQ,8IAA8I,CAAC,4IAI1I,UAAU,QAAQ,SAAS,CAAC,IAAI,UAAU,QAAQ,SAAS,CAAC,OAAO,UAAU,QAAQ,QAAQ,CAAC;AAE9H,SAAgB,sBAAkG,QAAyD;CACzK,MAAM,2BAAW,IAAI,KAA4C;CACjE,KAAK,MAAM,KAAK,QAAQ;EACtB,MAAM,MAAM,EAAE,eAAe,EAAE;EAC/B,IAAI,CAAC,SAAS,IAAI,IAAI,EACpB,SAAS,IAAI,KAAK;GAAE,MAAM;GAAK,QAAQ,EAAE;GAAE,CAAC;EAC9C,SAAS,IAAI,IAAI,CAAE,OAAO,KAAK,EAAE;;CAEnC,OAAO;;AAQT,eAAsB,UACpB,QACA,OAA2B,EAAE,EACL;CACxB,MAAM,aAAa,sBAAsB,OAAO;CAChD,MAAM,SAAS,KAAK,UAAU,EAAE;CAChC,MAAM,QAAQ,KAAK,SAAS,EAAE;CAE9B,IAAI,WAAW,SAAS,KAAK,OAAO,WAAW,GAAG;EAChD,MAAM,GAAG,SAAS,CAAC,GAAG,WAAW,SAAS,CAAC,CAAC;EAC5C,MAAM,SAAS,MAAM,EAAE,OAAO;GAC5B,SAAS,GAAG,MAAM;GAClB,SAAS,CACP,GAAG,MAAM,OAAO,KAAI,OAAM;IACxB,OAAO,EAAE,cAAc,GAAG,EAAE,KAAK,mCAAmC,EAAE;IACtE,OAAO,EAAE;IACT,MAAM,EAAE;IACT,EAAE,EACH,GAAG,MACJ;GACF,CAAC;EACF,OAAO,EAAE,SAAS,OAAO,GAAG,OAAO;;CAGrC,MAAM,iBAAiB,MAAM,EAAE,OAAO;EACpC,SAAS;EACT,SAAS;GACP,GAAG;GACH,GAAG,MAAM,KAAK,WAAW,SAAS,GAAG,CAAC,KAAK,EAAE,MAAM,QAAQ,WAAW;IACpE,OAAO;IACP,OAAO;IACP,MAAM,GAAG,GAAG,OAAO;IACpB,EAAE;GACH,GAAG;GACJ;EACF,CAAC;CAEF,IAAI,EAAE,SAAS,eAAe,EAC5B,OAAO;CAET,MAAM,cAAc;CACpB,IAAI,OAAO,MAAK,MAAK,EAAE,UAAU,YAAY,IAAI,MAAM,MAAK,MAAK,EAAE,UAAU,YAAY,EACvF,OAAO;CAET,MAAM,QAAQ,WAAW,IAAI,YAAY;CACzC,MAAM,cAAc,MAAM,EAAE,OAAO;EACjC,SAAS,iBAAiB,MAAM,KAAK;EACrC,SAAS,MAAM,OAAO,KAAI,OAAM;GAC9B,OAAO,EAAE,cAAc,GAAG,EAAE,KAAK,mCAAmC,EAAE;GACtE,OAAO,EAAE;GACT,MAAM,EAAE;GACT,EAAE;EACJ,CAAC;CAEF,OAAO,EAAE,SAAS,YAAY,GAAG,OAAO"}
|
|
@@ -1,10 +1,12 @@
|
|
|
1
|
+
import { i as GIT_PLUS_PREFIX_RE, o as GIT_SUFFIX_RE } from "./regex.mjs";
|
|
1
2
|
import { i as readPackageJsonSafe } from "./package-json.mjs";
|
|
2
3
|
import { existsSync, readFileSync, readdirSync } from "node:fs";
|
|
3
4
|
import { join, resolve } from "pathe";
|
|
5
|
+
const STATIC_REGEX_3 = /\/?\*+$/;
|
|
4
6
|
const QUOTE_PREFIX_RE = /^['"]/;
|
|
5
7
|
const QUOTE_SUFFIX_RE = /['"]$/;
|
|
6
8
|
function readRepoUrl(pkg) {
|
|
7
|
-
return typeof pkg.repository === "string" ? pkg.repository : pkg.repository?.url?.replace(
|
|
9
|
+
return typeof pkg.repository === "string" ? pkg.repository : pkg.repository?.url?.replace(GIT_PLUS_PREFIX_RE, "").replace(GIT_SUFFIX_RE, "");
|
|
8
10
|
}
|
|
9
11
|
function readWorkspacePatterns(cwd, pkg) {
|
|
10
12
|
let patterns = [];
|
|
@@ -33,7 +35,7 @@ function detectMonorepoPackages(cwd) {
|
|
|
33
35
|
if (patterns.length === 0) return null;
|
|
34
36
|
const packages = [];
|
|
35
37
|
for (const pattern of patterns) {
|
|
36
|
-
const scanDir = resolve(cwd, pattern.replace(
|
|
38
|
+
const scanDir = resolve(cwd, pattern.replace(STATIC_REGEX_3, ""));
|
|
37
39
|
if (!existsSync(scanDir)) continue;
|
|
38
40
|
const directResult = readPackageJsonSafe(join(scanDir, "package.json"));
|
|
39
41
|
if (directResult) {
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"monorepo.mjs","names":[],"sources":["../../src/core/monorepo.ts"],"sourcesContent":["/**\n * Monorepo detection — discovers public packages in a workspace root.\n * Used by author flow to drive multi-package skill generation.\n */\n\nimport { existsSync, readdirSync, readFileSync } from 'node:fs'\nimport { join, resolve } from 'pathe'\nimport { readPackageJsonSafe } from './package-json.ts'\n\nconst QUOTE_PREFIX_RE = /^['\"]/\nconst QUOTE_SUFFIX_RE = /['\"]$/\n\nexport interface MonorepoPackage {\n name: string\n version: string\n description?: string\n repoUrl?: string\n dir: string\n}\n\nfunction readRepoUrl(pkg: Record<string, any>): string | undefined {\n return typeof pkg.repository === 'string'\n ? pkg.repository\n : pkg.repository?.url?.replace(
|
|
1
|
+
{"version":3,"file":"monorepo.mjs","names":[],"sources":["../../src/core/monorepo.ts"],"sourcesContent":["/**\n * Monorepo detection — discovers public packages in a workspace root.\n * Used by author flow to drive multi-package skill generation.\n */\n\nimport { existsSync, readdirSync, readFileSync } from 'node:fs'\nimport { join, resolve } from 'pathe'\nimport { readPackageJsonSafe } from './package-json.ts'\nimport { GIT_PLUS_PREFIX_RE, GIT_SUFFIX_RE } from './regex.ts'\n\nconst STATIC_REGEX_3 = /\\/?\\*+$/\n\nconst QUOTE_PREFIX_RE = /^['\"]/\nconst QUOTE_SUFFIX_RE = /['\"]$/\n\nexport interface MonorepoPackage {\n name: string\n version: string\n description?: string\n repoUrl?: string\n dir: string\n}\n\nfunction readRepoUrl(pkg: Record<string, any>): string | undefined {\n return typeof pkg.repository === 'string'\n ? pkg.repository\n : pkg.repository?.url?.replace(GIT_PLUS_PREFIX_RE, '').replace(GIT_SUFFIX_RE, '')\n}\n\nfunction readWorkspacePatterns(cwd: string, pkg: Record<string, any>): string[] {\n let patterns: string[] = []\n\n if (Array.isArray(pkg.workspaces))\n patterns = pkg.workspaces\n else if (pkg.workspaces?.packages)\n patterns = pkg.workspaces.packages\n\n if (patterns.length === 0) {\n const pnpmWs = join(cwd, 'pnpm-workspace.yaml')\n if (existsSync(pnpmWs)) {\n const lines = readFileSync(pnpmWs, 'utf-8').split('\\n')\n for (const line of lines) {\n const trimmed = line.trim()\n if (!trimmed.startsWith('-'))\n continue\n const value = trimmed.slice(1).trim().replace(QUOTE_PREFIX_RE, '').replace(QUOTE_SUFFIX_RE, '')\n if (value)\n patterns.push(value)\n }\n }\n }\n\n return patterns\n}\n\n/**\n * Detect public (non-private) packages declared by a workspace root.\n * Returns null if `cwd` is not a private workspace root or has no public\n * packages. Supports `package.json#workspaces` (array or `{ packages }`)\n * and `pnpm-workspace.yaml`.\n */\nexport function detectMonorepoPackages(cwd: string): MonorepoPackage[] | null {\n const rootResult = readPackageJsonSafe(join(cwd, 'package.json'))\n if (!rootResult)\n return null\n\n const pkg = rootResult.parsed as Record<string, any>\n if (!pkg.private)\n return null\n\n const patterns = readWorkspacePatterns(cwd, pkg)\n if (patterns.length === 0)\n return null\n\n const packages: MonorepoPackage[] = []\n\n for (const pattern of patterns) {\n const base = pattern.replace(STATIC_REGEX_3, '')\n const scanDir = resolve(cwd, base)\n if (!existsSync(scanDir))\n continue\n\n const directResult = readPackageJsonSafe(join(scanDir, 'package.json'))\n if (directResult) {\n const directPkg = directResult.parsed as Record<string, any>\n if (!directPkg.private && directPkg.name) {\n packages.push({\n name: directPkg.name,\n version: directPkg.version || '0.0.0',\n description: directPkg.description,\n repoUrl: readRepoUrl(directPkg),\n dir: scanDir,\n })\n continue\n }\n }\n\n for (const entry of readdirSync(scanDir, { withFileTypes: true })) {\n if (!entry.isDirectory())\n continue\n const childResult = readPackageJsonSafe(join(scanDir, entry.name, 'package.json'))\n if (!childResult)\n continue\n\n const childPkg = childResult.parsed as Record<string, any>\n if (childPkg.private || !childPkg.name)\n continue\n\n packages.push({\n name: childPkg.name,\n version: childPkg.version || '0.0.0',\n description: childPkg.description,\n repoUrl: readRepoUrl(childPkg),\n dir: join(scanDir, entry.name),\n })\n }\n }\n\n return packages.length > 0 ? packages : null\n}\n"],"mappings":";;;;;;;AAUA,SAAM,YAAA,KAAiB;CAEvB,OAAM,OAAA,IAAA,eAAkB,WAAA,IAAA,aAAA,IAAA,YAAA,KAAA,QAAA,oBAAA,GAAA,CAAA,QAAA,eAAA,GAAA;;AAWxB,SAAS,sBAA0D,KAAA,KAAA;CACjE,IAAA,WAAc,EAAA;;MAKhB,IAAS,IAAA,YAAA,UAAmC,WAAoC,IAAA,WAAA;CAC9E,IAAI,SAAA,WAAuB,GAAA;EAE3B,MAAI,SAAM,KAAQ,KAAI,sBACT;MACR,WAAQ,OAAA,EAAY;GAGzB,MAAI,QAAS,aAAc,QAAA,QAAA,CAAA,MAAA,KAAA;GACzB,KAAM,MAAA,QAAc,OAAK;IACzB,MAAI,UAAW,KAAO,MAAE;IACtB,IAAA,CAAM,QAAQ,WAAA,IAAa,EAAA;IAC3B,MAAK,QAAM,QAAQ,MAAO,EAAA,CAAA,MAAA,CAAA,QAAA,iBAAA,GAAA,CAAA,QAAA,iBAAA,GAAA;IACxB,IAAA,OAAM,SAAU,KAAK,MAAM;;;;;;SAU1B,uBAAA,KAAA;;;;;;;;CAST,KAAA,MAAgB,WAAA,UAAuB;EACrC,MAAM,UAAA,QAAa,KAAA,QAAA,QAAyB,gBAAK,GAAgB,CAAA;EACjE,IAAK,CAAA,WACH,QAAO,EAAA;EAET,MAAM,eAAM,oBAAW,KAAA,SAAA,eAAA,CAAA;EACvB,IAAK,cACH;GAEF,MAAM,YAAW,aAAA;GACjB,IAAI,CAAA,UAAS,WACX,UAAO,MAAA;IAET,SAAM,KAA8B;KAEpC,MAAK,UAAM;KAET,SAAM,UAAU,WADH;KAEb,aAAgB,UACd;KAEF,SAAM,YAAe,UAAA;KACrB,KAAI;KACF,CAAA;IACA;;;OAGI,MAAA,SAAS,YAAU,SAAW,EAAA,eAAA,MAAA,CAAA,EAAA;OAC9B,CAAA,MAAA,aAAa,EAAU;SACvB,cAAS,oBAAsB,KAAA,SAAA,MAAA,MAAA,eAAA,CAAA;OAC/B,CAAA,aAAK;SACL,WAAA,YAAA;OACF,SAAA,WAAA,CAAA,SAAA,MAAA;;;IAIJ,SAAW,SAAS,WAAA;IAClB,aAAW,SAAA;IAEX,SAAM,YAAc,SAAA;IACpB,KAAK,KAAA,SACH,MAAA,KAAA;IAEF,CAAA;;;QAKE,SAAM,SAAS,IAAA,WAAA;;SAGf,0BAA8B"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"package-json.mjs","names":[],"sources":["../../src/core/package-json.ts"],"sourcesContent":["import { existsSync, readFileSync, writeFileSync } from 'node:fs'\nimport { applyEdits, modify, parseTree } from 'jsonc-parser'\n\nexport interface EditOptions {\n /** Formatting options for inserted content */\n tabSize?: number\n insertSpaces?: boolean\n}\n\nconst defaultEditOptions: EditOptions = { tabSize: 2, insertSpaces: true }\n\n// ── Cached reader ──────────────────────────────────────────────\n\nconst cache = new Map<string, { raw: string, parsed: Record<string, unknown> }>()\n\n/**\n * Read and parse a package.json, returning cached result on repeat calls.\n * Throws if the file does not exist.\n */\nexport function readPackageJson(pkgPath: string): { raw: string, parsed: Record<string, unknown> } {\n const hit = cache.get(pkgPath)\n if (hit)\n return hit\n const raw = readFileSync(pkgPath, 'utf-8')\n const parsed = JSON.parse(raw) as Record<string, unknown>\n const entry = { raw, parsed }\n cache.set(pkgPath, entry)\n return entry\n}\n\n/**\n * Same as readPackageJson but returns null when the file is missing or unparseable.\n */\nexport function readPackageJsonSafe(pkgPath: string): { raw: string, parsed: Record<string, unknown> } | null {\n if (cache.has(pkgPath))\n return cache.get(pkgPath)!\n if (!existsSync(pkgPath))\n return null\n try {\n return readPackageJson(pkgPath)\n }\n catch {\n return null\n }\n}\n\n/**\n * Drop any cached entry so the next read hits disk.\n */\nexport function invalidatePackageJson(pkgPath: string): void {\n cache.delete(pkgPath)\n}\n\n/**\n *
|
|
1
|
+
{"version":3,"file":"package-json.mjs","names":[],"sources":["../../src/core/package-json.ts"],"sourcesContent":["import { existsSync, readFileSync, writeFileSync } from 'node:fs'\nimport { applyEdits, modify, parseTree } from 'jsonc-parser'\n\nexport interface EditOptions {\n /** Formatting options for inserted content */\n tabSize?: number\n insertSpaces?: boolean\n}\n\nconst defaultEditOptions: EditOptions = { tabSize: 2, insertSpaces: true }\n\n// ── Cached reader ──────────────────────────────────────────────\n\nconst cache = new Map<string, { raw: string, parsed: Record<string, unknown> }>()\n\n/**\n * Read and parse a package.json, returning cached result on repeat calls.\n * Throws if the file does not exist.\n */\nexport function readPackageJson(pkgPath: string): { raw: string, parsed: Record<string, unknown> } {\n const hit = cache.get(pkgPath)\n if (hit)\n return hit\n const raw = readFileSync(pkgPath, 'utf-8')\n const parsed = JSON.parse(raw) as Record<string, unknown>\n const entry = { raw, parsed }\n cache.set(pkgPath, entry)\n return entry\n}\n\n/**\n * Same as readPackageJson but returns null when the file is missing or unparseable.\n */\nexport function readPackageJsonSafe(pkgPath: string): { raw: string, parsed: Record<string, unknown> } | null {\n if (cache.has(pkgPath))\n return cache.get(pkgPath)!\n if (!existsSync(pkgPath))\n return null\n try {\n return readPackageJson(pkgPath)\n }\n catch {\n return null\n }\n}\n\n/**\n * Drop any cached entry so the next read hits disk.\n */\nexport function invalidatePackageJson(pkgPath: string): void {\n cache.delete(pkgPath)\n}\n\n/**\n * Drop all cached entries. Useful for tests.\n */\nexport function clearPackageJsonCache(): void {\n cache.clear()\n}\n\n// ── JSON editing helpers ───────────────────────────────────────\n\n/**\n * Set a value at a JSON path, preserving all surrounding formatting.\n * Returns the modified file content as a string.\n */\nexport function editJsonProperty(raw: string, path: (string | number)[], value: unknown, options?: EditOptions): string {\n const opts = { ...defaultEditOptions, ...options }\n const edits = modify(raw, path, value, {\n formattingOptions: { tabSize: opts.tabSize!, insertSpaces: opts.insertSpaces! },\n })\n return applyEdits(raw, edits)\n}\n\n/**\n * Read a package.json, apply an edit function, write it back, and invalidate the cache.\n * The edit function receives the raw text and parsed object,\n * and returns the new raw text (or null to skip writing).\n */\nexport function patchPackageJson(\n pkgPath: string,\n editFn: (raw: string, pkg: Record<string, unknown>) => string | null,\n): boolean {\n const { raw, parsed } = readPackageJson(pkgPath)\n const result = editFn(raw, parsed)\n if (result === null)\n return false\n writeFileSync(pkgPath, result)\n invalidatePackageJson(pkgPath)\n return true\n}\n\n/**\n * Append a value to a JSON array at the given path, preserving formatting.\n * Inserts in sorted order if the array contains strings.\n */\nexport function appendToJsonArray(raw: string, path: string[], value: string, options?: EditOptions): string {\n const opts = { ...defaultEditOptions, ...options }\n const tree = parseTree(raw)\n if (!tree)\n return editJsonProperty(raw, path, [value], opts)\n\n // Walk to the target array node\n let node = tree\n for (const key of path) {\n const child = node.children?.find(c =>\n c.type === 'property' && c.children?.[0]?.value === key,\n )\n if (!child?.children?.[1])\n return editJsonProperty(raw, path, [value], opts)\n node = child.children[1]\n }\n\n if (node.type !== 'array' || !node.children)\n return editJsonProperty(raw, path, [value], opts)\n\n // Find sorted insertion index (only for string-only arrays)\n const allStrings = node.children.every(c => typeof c.value === 'string')\n let idx = node.children.length\n if (allStrings) {\n const items = node.children.map(c => c.value as string)\n for (let i = 0; i < items.length; i++) {\n if (value.localeCompare(items[i]!) < 0) {\n idx = i\n break\n }\n }\n }\n\n const edits = modify(raw, [...path, idx], value, {\n formattingOptions: { tabSize: opts.tabSize!, insertSpaces: opts.insertSpaces! },\n isArrayInsertion: true,\n })\n return applyEdits(raw, edits)\n}\n"],"mappings":";;AASA,MAAM,qBAAkC;CAAE,SAAS;CAAG,cAAc;CAAM;AAI1E,MAAM,wBAAQ,IAAI,KAA+D;;;;CAMjF,MAAA,MAAgB,aAAgB,SAAmE,QAAA;CACjG,MAAM,QAAM;EACZ;EAEA,QAAM,KAAM,MAAA,IAAA;EAEZ;OAAgB,IAAA,SAAA,MAAA;QAAK;;SAEd,oBAAA,SAAA;;;;;SAMO;EACd,OAAI;;;SAOE,sBAAA,SAAA;OACJ,OAAO,QAAA;;;;;EAOX,GAAA;EACE;;;;;;SAiBM,iBAAO,SAAA,QAAA;OAAK,EAAA,KAAA,WAAA,gBAAA,QAAA;OAAuB,SAAA,OAAA,KAAA,OAAA;KAAS,WAAA,MAAA,OAAA;CAIlD,cAAO,SAHO,OAAO;uBACgB,QAAA;QAAU;;;;;;;CAUjD,MAAA,OAAgB,UAAA,IACd;CAGA,IAAA,CAAA,MAAQ,OAAK,iBAAW,KAAgB,MAAA,CAAA,MAAQ,EAAA,KAAA;CAChD,IAAA,OAAM;CACN,KAAI,MAAA,OAAW,MACb;EACF,MAAA,QAAc,KAAA,UAAgB,MAAA,MAAA,EAAA,SAAA,cAAA,EAAA,WAAA,IAAA,UAAA,IAAA;EAC9B,IAAA,CAAA,OAAA,WAAsB,IAAA,OAAQ,iBAAA,KAAA,MAAA,CAAA,MAAA,EAAA,KAAA;EAC9B,OAAO,MAAA,SAAA;;;;;;EAOT,MAAA,QAAgB,KAAA,SAAkB,KAAa,MAAgB,EAAA,MAAe;EAC5E,KAAM,IAAA,IAAO,GAAA,IAAA,MAAA,QAAA,KAAA,IAAA,MAAA,cAAA,MAAA,GAAA,GAAA,GAAA;GAAE,MAAG;GAAoB;;;CAEtC,OAAK,WACI,KAAA,OAAA,KAAiB,CAAA,GAAA,MAAK,IAAO,EAAA,OAAQ;EAG9C,mBAAW;GACX,SAAW,KAAA;GACT,cAAc,KAAK;GAGnB;EAEA,kBAAa;;;SAQX,uBAAoB,GAAA,oBAAA,GAAA,oBAAA,GAAA,qBAAA"}
|
package/dist/_chunks/paths.mjs
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { existsSync } from "node:fs";
|
|
2
|
-
import { homedir } from "node:os";
|
|
3
2
|
import { join } from "pathe";
|
|
3
|
+
import { homedir } from "node:os";
|
|
4
4
|
const SHARED_SKILLS_DIR = ".skills";
|
|
5
5
|
const SKILL_INTERNAL_DIRNAME = ".skilld";
|
|
6
6
|
const SKILL_INTERNAL_FILENAME = "_SKILL.md";
|
|
@@ -10,11 +10,9 @@ const CACHE_DIR = join(homedir(), ".skilld");
|
|
|
10
10
|
const REFERENCES_DIR = join(CACHE_DIR, "references");
|
|
11
11
|
const REPOS_DIR = join(CACHE_DIR, "repos");
|
|
12
12
|
const LLM_CACHE_DIR = join(CACHE_DIR, "llm-cache");
|
|
13
|
-
join(CACHE_DIR, "skills");
|
|
14
|
-
join(CACHE_DIR, "git-skills");
|
|
15
|
-
join(CACHE_DIR, "embeddings.db");
|
|
16
13
|
const CONFIG_PATH = join(CACHE_DIR, CONFIG_FILENAME);
|
|
17
14
|
const PI_AI_AUTH_PATH = join(CACHE_DIR, "pi-ai-auth.json");
|
|
15
|
+
const AUTH_PATH = join(CACHE_DIR, "auth.json");
|
|
18
16
|
function getSharedSkillsDir(cwd = process.cwd()) {
|
|
19
17
|
const dir = join(cwd, SHARED_SKILLS_DIR);
|
|
20
18
|
return existsSync(dir) ? dir : null;
|
|
@@ -44,6 +42,6 @@ function getRepoCacheDir(owner, repo) {
|
|
|
44
42
|
function getPackageDbPath(name, version) {
|
|
45
43
|
return join(getReferencesDir(name, version), "search.db");
|
|
46
44
|
}
|
|
47
|
-
export {
|
|
45
|
+
export { skillRefsSection as _, LOCK_FILENAME as a, REPOS_DIR as c, getRepoCacheDir as d, getSharedSkillsDir as f, skillLogDir as g, skillInternalFile as h, LLM_CACHE_DIR as i, SHARED_SKILLS_DIR as l, skillInternalDir as m, CACHE_DIR as n, PI_AI_AUTH_PATH as o, lockfilePath as p, CONFIG_PATH as r, REFERENCES_DIR as s, AUTH_PATH as t, getPackageDbPath as u };
|
|
48
46
|
|
|
49
47
|
//# sourceMappingURL=paths.mjs.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"paths.mjs","names":[],"sources":["../../src/core/paths.ts"],"sourcesContent":["/**\n * Project layout: every `~/.skilld/...` and `.claude/skills/...` path lives here.\n *\n * Two layers:\n * 1. Global cache under `~/.skilld/` (references, repos, llm-cache, etc.)\n * 2. Per-skill internals: `<skillDir>/.skilld/` holds reference symlinks,\n * logs, and the canonical `_SKILL.md`. The lockfile sits as a sibling\n * of skill dirs as `skilld-lock.yaml`.\n *\n * Per-agent target dirs (`.claude/skills/`, `.cursor/skills/`, ...) are owned\n * by the agent registry (`src/agent/registry.ts`); this module exposes the\n * agent-agnostic `.skills/` shared dir and helpers that compose with target dirs.\n */\n\nimport { existsSync } from 'node:fs'\nimport { homedir } from 'node:os'\nimport { join } from 'pathe'\n\n// ── Project-relative names ──\n\n/** Shared, agent-agnostic skills directory at project root */\nexport const SHARED_SKILLS_DIR = '.skills'\n\n/** Per-skill internals directory (cache symlinks, logs, prompts, _SKILL.md) */\nexport const SKILL_INTERNAL_DIRNAME = '.skilld'\n\n/** Canonical SKILL.md copy inside the per-skill internals dir (frontmatter source of truth) */\nexport const SKILL_INTERNAL_FILENAME = '_SKILL.md'\n\n/** Lockfile sibling of skill directories */\nexport const LOCK_FILENAME = 'skilld-lock.yaml'\n\n/** Config filename inside the global cache */\nexport const CONFIG_FILENAME = 'config.yaml'\n\n// ── Global cache layout (~/.skilld/) ──\n\n/** Root of the global cache */\nexport const CACHE_DIR: string = join(homedir(), '.skilld')\n\n/** References subdirectory: `~/.skilld/references/<pkg>@<version>/` */\nexport const REFERENCES_DIR: string = join(CACHE_DIR, 'references')\n\n/** Repo-level cache (issues, discussions, releases shared across monorepo packages) */\nexport const REPOS_DIR: string = join(CACHE_DIR, 'repos')\n\n/** LLM output cache: `~/.skilld/llm-cache/<sha256>.json` */\nexport const LLM_CACHE_DIR: string = join(CACHE_DIR, 'llm-cache')\n\n/** Global
|
|
1
|
+
{"version":3,"file":"paths.mjs","names":[],"sources":["../../src/core/paths.ts"],"sourcesContent":["/**\n * Project layout: every `~/.skilld/...` and `.claude/skills/...` path lives here.\n *\n * Two layers:\n * 1. Global cache under `~/.skilld/` (references, repos, llm-cache, etc.)\n * 2. Per-skill internals: `<skillDir>/.skilld/` holds reference symlinks,\n * logs, and the canonical `_SKILL.md`. The lockfile sits as a sibling\n * of skill dirs as `skilld-lock.yaml`.\n *\n * Per-agent target dirs (`.claude/skills/`, `.cursor/skills/`, ...) are owned\n * by the agent registry (`src/agent/registry.ts`); this module exposes the\n * agent-agnostic `.skills/` shared dir and helpers that compose with target dirs.\n */\n\nimport { existsSync } from 'node:fs'\nimport { homedir } from 'node:os'\nimport { join } from 'pathe'\n\n// ── Project-relative names ──\n\n/** Shared, agent-agnostic skills directory at project root */\nexport const SHARED_SKILLS_DIR = '.skills'\n\n/** Per-skill internals directory (cache symlinks, logs, prompts, _SKILL.md) */\nexport const SKILL_INTERNAL_DIRNAME = '.skilld'\n\n/** Canonical SKILL.md copy inside the per-skill internals dir (frontmatter source of truth) */\nexport const SKILL_INTERNAL_FILENAME = '_SKILL.md'\n\n/** Lockfile sibling of skill directories */\nexport const LOCK_FILENAME = 'skilld-lock.yaml'\n\n/** Config filename inside the global cache */\nexport const CONFIG_FILENAME = 'config.yaml'\n\n// ── Global cache layout (~/.skilld/) ──\n\n/** Root of the global cache */\nexport const CACHE_DIR: string = join(homedir(), '.skilld')\n\n/** References subdirectory: `~/.skilld/references/<pkg>@<version>/` */\nexport const REFERENCES_DIR: string = join(CACHE_DIR, 'references')\n\n/** Repo-level cache (issues, discussions, releases shared across monorepo packages) */\nexport const REPOS_DIR: string = join(CACHE_DIR, 'repos')\n\n/** LLM output cache: `~/.skilld/llm-cache/<sha256>.json` */\nexport const LLM_CACHE_DIR: string = join(CACHE_DIR, 'llm-cache')\n\n/** Global config file */\nexport const CONFIG_PATH: string = join(CACHE_DIR, CONFIG_FILENAME)\n\n/** pi-ai auth credentials */\nexport const PI_AI_AUTH_PATH: string = join(CACHE_DIR, 'pi-ai-auth.json')\n\n/** CLI auth marker (`~/.skilld/auth.json`, 0600). Stores tokens directly only when keychain unavailable. */\nexport const AUTH_PATH: string = join(CACHE_DIR, 'auth.json')\n\n// ── Helpers ──\n\n/** Returns the shared skills directory path if `.skills/` exists at project root, else null */\nexport function getSharedSkillsDir(cwd: string = process.cwd()): string | null {\n const dir = join(cwd, SHARED_SKILLS_DIR)\n return existsSync(dir) ? dir : null\n}\n\n/** Path to the lockfile inside a skills directory */\nexport function lockfilePath(skillsDir: string): string {\n return join(skillsDir, LOCK_FILENAME)\n}\n\n/** Per-skill internals dir (`<skillDir>/.skilld`) */\nexport function skillInternalDir(skillDir: string): string {\n return join(skillDir, SKILL_INTERNAL_DIRNAME)\n}\n\n/** Per-skill canonical SKILL.md (`<skillDir>/.skilld/_SKILL.md`) */\nexport function skillInternalFile(skillDir: string): string {\n return join(skillDir, SKILL_INTERNAL_DIRNAME, SKILL_INTERNAL_FILENAME)\n}\n\n/** Per-skill log dir (`<skillDir>/.skilld/logs`) */\nexport function skillLogDir(skillDir: string): string {\n return join(skillDir, SKILL_INTERNAL_DIRNAME, 'logs')\n}\n\n/** Per-skill section dir (`<skillDir>/.skilld/<section>`), e.g. issues/discussions/releases/docs */\nexport function skillRefsSection(skillDir: string, section: string): string {\n return join(skillDir, SKILL_INTERNAL_DIRNAME, section)\n}\n\n/** References cache dir for a `name@version` */\nexport function getReferencesDir(name: string, version: string): string {\n return join(REFERENCES_DIR, `${name}@${version}`)\n}\n\n/** Repo cache dir with path-traversal validation */\nexport function getRepoCacheDir(owner: string, repo: string): string {\n if (owner.includes('..') || repo.includes('..') || owner.includes('/') || repo.includes('/'))\n throw new Error(`Invalid repo path: ${owner}/${repo}`)\n return join(REPOS_DIR, owner, repo)\n}\n\n/** search.db path for a `name@version` */\nexport function getPackageDbPath(name: string, version: string): string {\n return join(getReferencesDir(name, version), 'search.db')\n}\n"],"mappings":";;;;;;;;;AAqBA,MAAa,iBAAA,KAAoB,WAAA,aAAA;AAGjC,MAAa,YAAA,KAAA,WAAyB,QAAA;AAGtC,MAAa,gBAAA,KAAA,WAA0B,YAAA;AAGvC,MAAa,cAAA,KAAgB,WAAA,gBAAA;AAG7B,MAAa,kBAAkB,KAAA,WAAA,kBAAA;AAK/B,MAAa,YAAoB,KAAK,WAAW,YAAU;AAG3D,SAAa,mBAA8B,MAAA,QAAW,KAAA,EAAA;;CAGtD,OAAa,WAAoB,IAAK,GAAA,MAAA;;;CAMtC,OAAa,KAAA,WAAsB,cAAgB;;;CAMnD,OAAa,KAAA,UAAyB,uBAAuB;;SAMrD,kBAAgB,UAAA;CACtB,OAAO,KAAA,UAAe,wBAAS,wBAAA;;AAIjC,SAAgB,YAAA,UAAa;CAC3B,OAAO,KAAK,UAAA,wBAAyB,OAAA;;AAIvC,SAAgB,iBAAiB,UAA0B,SAAA;CACzD,OAAO,KAAK,UAAU,wBAAuB,QAAA;;AAI/C,SAAgB,iBAAA,MAAkB,SAA0B;CAC1D,OAAO,KAAK,gBAAU,GAAA,KAAA,GAAA,UAAwB;;AAIhD,SAAgB,gBAAY,OAA0B,MAAA;CACpD,IAAA,MAAO,SAAK,KAAU,IAAA,KAAA,SAAA,KAAwB,IAAA,MAAO,SAAA,IAAA,IAAA,KAAA,SAAA,IAAA,EAAA,MAAA,IAAA,MAAA,sBAAA,MAAA,GAAA,OAAA;;;SAK9C,iBAAe,MAAA,SAAA;;;SAKf,oBAAqB,GAAG,iBAAQ,GAAU,aAAA,GAAA,mBAAA,GAAA,sBAAA,GAAA,eAAA,GAAA,qBAAA,GAAA,iBAAA,GAAA,qBAAA,GAAA,oBAAA,GAAA,aAAA,GAAA,mBAAA,GAAA,gBAAA,GAAA,eAAA,GAAA,kBAAA,GAAA,aAAA,GAAA,oBAAA"}
|