skilld 1.5.0 → 1.5.2
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/agent.mjs +2 -2
- package/dist/_chunks/assemble.mjs +2 -0
- package/dist/_chunks/assemble.mjs.map +1 -1
- package/dist/_chunks/author.mjs +13 -11
- package/dist/_chunks/author.mjs.map +1 -1
- package/dist/_chunks/cache.mjs +6 -42
- package/dist/_chunks/cache.mjs.map +1 -1
- package/dist/_chunks/cache2.mjs +3 -1
- package/dist/_chunks/cache2.mjs.map +1 -1
- package/dist/_chunks/cli-helpers.mjs +31 -102
- package/dist/_chunks/cli-helpers.mjs.map +1 -1
- package/dist/_chunks/cli-helpers2.mjs +12 -0
- package/dist/_chunks/core.mjs +1 -0
- package/dist/_chunks/embedding-cache.mjs +4 -60
- package/dist/_chunks/embedding-cache2.mjs +61 -0
- package/dist/_chunks/embedding-cache2.mjs.map +1 -0
- package/dist/_chunks/index.d.mts +13 -21
- package/dist/_chunks/index.d.mts.map +1 -1
- package/dist/_chunks/index2.d.mts +32 -600
- package/dist/_chunks/index2.d.mts.map +1 -1
- package/dist/_chunks/index3.d.mts +615 -0
- package/dist/_chunks/index3.d.mts.map +1 -0
- package/dist/_chunks/install.mjs +12 -9
- package/dist/_chunks/install.mjs.map +1 -1
- package/dist/_chunks/list.mjs +3 -1
- package/dist/_chunks/list.mjs.map +1 -1
- package/dist/_chunks/lockfile.mjs +14 -1
- package/dist/_chunks/lockfile.mjs.map +1 -1
- package/dist/_chunks/package-json.mjs +107 -0
- package/dist/_chunks/package-json.mjs.map +1 -0
- package/dist/_chunks/pool.mjs +2 -123
- package/dist/_chunks/pool2.mjs +118 -0
- package/dist/_chunks/pool2.mjs.map +1 -0
- package/dist/_chunks/prepare.mjs +34 -78
- package/dist/_chunks/prepare.mjs.map +1 -1
- package/dist/_chunks/prepare2.mjs +94 -0
- package/dist/_chunks/prepare2.mjs.map +1 -0
- package/dist/_chunks/retriv.mjs +172 -0
- package/dist/_chunks/retriv.mjs.map +1 -0
- package/dist/_chunks/search-interactive.mjs +5 -3
- package/dist/_chunks/search-interactive.mjs.map +1 -1
- package/dist/_chunks/search.mjs +13 -320
- package/dist/_chunks/search2.mjs +319 -0
- package/dist/_chunks/search2.mjs.map +1 -0
- package/dist/_chunks/setup.mjs +4 -2
- package/dist/_chunks/setup.mjs.map +1 -1
- package/dist/_chunks/skills.mjs +1 -1
- package/dist/_chunks/sources.mjs +15 -18
- package/dist/_chunks/sources.mjs.map +1 -1
- package/dist/_chunks/sync-shared.mjs +3 -0
- package/dist/_chunks/sync-shared2.mjs +8 -6
- package/dist/_chunks/sync-shared2.mjs.map +1 -1
- package/dist/_chunks/sync.mjs +7 -7
- package/dist/_chunks/sync.mjs.map +1 -1
- package/dist/_chunks/sync2.mjs +22 -0
- package/dist/_chunks/uninstall.mjs +6 -2
- package/dist/_chunks/uninstall.mjs.map +1 -1
- package/dist/_chunks/wizard.mjs +186 -0
- package/dist/_chunks/wizard.mjs.map +1 -0
- package/dist/agent/index.mjs +2 -0
- package/dist/cache/index.d.mts +1 -1
- package/dist/cache/index.mjs +3 -1
- package/dist/cli-entry.d.mts +1 -0
- package/dist/cli-entry.mjs +11 -0
- package/dist/cli-entry.mjs.map +1 -0
- package/dist/cli.mjs +27 -192
- package/dist/cli.mjs.map +1 -1
- package/dist/index.d.mts +3 -3
- package/dist/index.mjs +4 -2
- package/dist/prepare.d.mts +1 -0
- package/dist/prepare.mjs +93 -0
- package/dist/prepare.mjs.map +1 -0
- package/dist/retriv/index.d.mts +2 -46
- package/dist/retriv/index.mjs +2 -171
- package/dist/sources/index.d.mts +1 -1
- package/dist/sources/index.mjs +1 -0
- package/dist/types.d.mts +1 -1
- package/package.json +1 -1
- package/dist/_chunks/embedding-cache.mjs.map +0 -1
- package/dist/_chunks/pool.mjs.map +0 -1
- package/dist/_chunks/search.mjs.map +0 -1
- package/dist/retriv/index.d.mts.map +0 -1
- package/dist/retriv/index.mjs.map +0 -1
|
@@ -1,12 +1,13 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { o as getModelName } from "./agent.mjs";
|
|
2
|
+
import { i as readPackageJsonSafe, n as editJsonProperty, r as patchPackageJson } from "./package-json.mjs";
|
|
2
3
|
import { n as yamlParseKV, r as yamlUnescape, t as yamlEscape } from "./yaml.mjs";
|
|
3
4
|
import { a as targets, i as getAgentVersion, n as detectProjectAgents, r as detectTargetAgent, t as detectInstalledAgents } from "./detect.mjs";
|
|
4
5
|
import { homedir } from "node:os";
|
|
5
6
|
import { join } from "pathe";
|
|
6
7
|
import { existsSync, mkdirSync, readFileSync, writeFileSync } from "node:fs";
|
|
8
|
+
import { parseTree } from "jsonc-parser";
|
|
7
9
|
import { fileURLToPath } from "node:url";
|
|
8
10
|
import * as p from "@clack/prompts";
|
|
9
|
-
import { applyEdits, modify, parseTree } from "jsonc-parser";
|
|
10
11
|
import { detectCurrentAgent } from "unagent/env";
|
|
11
12
|
import { dirname as dirname$1, resolve as resolve$1 } from "node:path";
|
|
12
13
|
//#region src/core/config.ts
|
|
@@ -18,6 +19,7 @@ const defaultFeatures = {
|
|
|
18
19
|
};
|
|
19
20
|
const CONFIG_DIR = join(homedir(), ".skilld");
|
|
20
21
|
const CONFIG_PATH = join(CONFIG_DIR, "config.yaml");
|
|
22
|
+
let configCache;
|
|
21
23
|
function hasConfig() {
|
|
22
24
|
return existsSync(CONFIG_PATH);
|
|
23
25
|
}
|
|
@@ -28,6 +30,11 @@ function hasCompletedWizard() {
|
|
|
28
30
|
return config.features !== void 0 || config.model !== void 0 || config.skipLlm !== void 0;
|
|
29
31
|
}
|
|
30
32
|
function readConfig() {
|
|
33
|
+
if (configCache) return {
|
|
34
|
+
...configCache,
|
|
35
|
+
features: configCache.features ? { ...configCache.features } : void 0,
|
|
36
|
+
projects: configCache.projects ? [...configCache.projects] : void 0
|
|
37
|
+
};
|
|
31
38
|
if (!existsSync(CONFIG_PATH)) return {};
|
|
32
39
|
const content = readFileSync(CONFIG_PATH, "utf-8");
|
|
33
40
|
const config = {};
|
|
@@ -71,6 +78,7 @@ function readConfig() {
|
|
|
71
78
|
...defaultFeatures,
|
|
72
79
|
...features
|
|
73
80
|
};
|
|
81
|
+
configCache = config;
|
|
74
82
|
return config;
|
|
75
83
|
}
|
|
76
84
|
function writeConfig(config) {
|
|
@@ -91,6 +99,7 @@ function writeConfig(config) {
|
|
|
91
99
|
for (const p of config.projects) yaml += ` - ${yamlEscape(p)}\n`;
|
|
92
100
|
}
|
|
93
101
|
writeFileSync(CONFIG_PATH, yaml, { mode: 384 });
|
|
102
|
+
configCache = void 0;
|
|
94
103
|
}
|
|
95
104
|
function updateConfig(updates) {
|
|
96
105
|
writeConfig({
|
|
@@ -119,73 +128,6 @@ function getRegisteredProjects() {
|
|
|
119
128
|
return readConfig().projects || [];
|
|
120
129
|
}
|
|
121
130
|
//#endregion
|
|
122
|
-
//#region src/core/package-json.ts
|
|
123
|
-
const defaultEditOptions = {
|
|
124
|
-
tabSize: 2,
|
|
125
|
-
insertSpaces: true
|
|
126
|
-
};
|
|
127
|
-
/**
|
|
128
|
-
* Set a value at a JSON path, preserving all surrounding formatting.
|
|
129
|
-
* Returns the modified file content as a string.
|
|
130
|
-
*/
|
|
131
|
-
function editJsonProperty(raw, path, value, options) {
|
|
132
|
-
const opts = {
|
|
133
|
-
...defaultEditOptions,
|
|
134
|
-
...options
|
|
135
|
-
};
|
|
136
|
-
return applyEdits(raw, modify(raw, path, value, { formattingOptions: {
|
|
137
|
-
tabSize: opts.tabSize,
|
|
138
|
-
insertSpaces: opts.insertSpaces
|
|
139
|
-
} }));
|
|
140
|
-
}
|
|
141
|
-
/**
|
|
142
|
-
* Read a package.json, apply an edit function, and write it back.
|
|
143
|
-
* The edit function receives the raw text and parsed object,
|
|
144
|
-
* and returns the new raw text (or null to skip writing).
|
|
145
|
-
*/
|
|
146
|
-
function patchPackageJson(pkgPath, editFn) {
|
|
147
|
-
const raw = readFileSync(pkgPath, "utf-8");
|
|
148
|
-
const result = editFn(raw, JSON.parse(raw));
|
|
149
|
-
if (result === null) return false;
|
|
150
|
-
writeFileSync(pkgPath, result);
|
|
151
|
-
return true;
|
|
152
|
-
}
|
|
153
|
-
/**
|
|
154
|
-
* Append a value to a JSON array at the given path, preserving formatting.
|
|
155
|
-
* Inserts in sorted order if the array contains strings.
|
|
156
|
-
*/
|
|
157
|
-
function appendToJsonArray(raw, path, value, options) {
|
|
158
|
-
const opts = {
|
|
159
|
-
...defaultEditOptions,
|
|
160
|
-
...options
|
|
161
|
-
};
|
|
162
|
-
const tree = parseTree(raw);
|
|
163
|
-
if (!tree) return editJsonProperty(raw, path, [value], opts);
|
|
164
|
-
let node = tree;
|
|
165
|
-
for (const key of path) {
|
|
166
|
-
const child = node.children?.find((c) => c.type === "property" && c.children?.[0]?.value === key);
|
|
167
|
-
if (!child?.children?.[1]) return editJsonProperty(raw, path, [value], opts);
|
|
168
|
-
node = child.children[1];
|
|
169
|
-
}
|
|
170
|
-
if (node.type !== "array" || !node.children) return editJsonProperty(raw, path, [value], opts);
|
|
171
|
-
const allStrings = node.children.every((c) => typeof c.value === "string");
|
|
172
|
-
let idx = node.children.length;
|
|
173
|
-
if (allStrings) {
|
|
174
|
-
const items = node.children.map((c) => c.value);
|
|
175
|
-
for (let i = 0; i < items.length; i++) if (value.localeCompare(items[i]) < 0) {
|
|
176
|
-
idx = i;
|
|
177
|
-
break;
|
|
178
|
-
}
|
|
179
|
-
}
|
|
180
|
-
return applyEdits(raw, modify(raw, [...path, idx], value, {
|
|
181
|
-
formattingOptions: {
|
|
182
|
-
tabSize: opts.tabSize,
|
|
183
|
-
insertSpaces: opts.insertSpaces
|
|
184
|
-
},
|
|
185
|
-
isArrayInsertion: true
|
|
186
|
-
}));
|
|
187
|
-
}
|
|
188
|
-
//#endregion
|
|
189
131
|
//#region src/version.ts
|
|
190
132
|
function findPackageJson() {
|
|
191
133
|
let dir = dirname$1(fileURLToPath(import.meta.url));
|
|
@@ -202,29 +144,6 @@ function findPackageJson() {
|
|
|
202
144
|
const version = JSON.parse(findPackageJson()).version;
|
|
203
145
|
//#endregion
|
|
204
146
|
//#region src/cli-helpers.ts
|
|
205
|
-
var cli_helpers_exports = /* @__PURE__ */ __exportAll({
|
|
206
|
-
MenuCancel: () => MenuCancel,
|
|
207
|
-
NO_MODELS_MESSAGE: () => NO_MODELS_MESSAGE,
|
|
208
|
-
OAUTH_NOTE: () => OAUTH_NOTE,
|
|
209
|
-
buildPrepareScript: () => buildPrepareScript,
|
|
210
|
-
formatStatus: () => formatStatus,
|
|
211
|
-
getInstalledGenerators: () => getInstalledGenerators,
|
|
212
|
-
getLastSynced: () => getLastSynced,
|
|
213
|
-
getRepoHint: () => getRepoHint,
|
|
214
|
-
groupModelsByProvider: () => groupModelsByProvider,
|
|
215
|
-
guard: () => guard,
|
|
216
|
-
introLine: () => introLine,
|
|
217
|
-
isInteractive: () => isInteractive,
|
|
218
|
-
isRunningInsideAgent: () => isRunningInsideAgent,
|
|
219
|
-
menuLoop: () => menuLoop,
|
|
220
|
-
pickModel: () => pickModel,
|
|
221
|
-
promptForAgent: () => promptForAgent,
|
|
222
|
-
relativeTime: () => relativeTime,
|
|
223
|
-
requireInteractive: () => requireInteractive,
|
|
224
|
-
resolveAgent: () => resolveAgent,
|
|
225
|
-
sharedArgs: () => sharedArgs,
|
|
226
|
-
suggestPrepareHook: () => suggestPrepareHook
|
|
227
|
-
});
|
|
228
147
|
const sharedArgs = {
|
|
229
148
|
global: {
|
|
230
149
|
type: "boolean",
|
|
@@ -499,15 +418,24 @@ async function pickModel(models, opts = {}) {
|
|
|
499
418
|
return p.isCancel(modelChoice) ? null : modelChoice;
|
|
500
419
|
}
|
|
501
420
|
/**
|
|
421
|
+
* Check if the prepare hook is already installed in package.json.
|
|
422
|
+
*/
|
|
423
|
+
function hasPrepareHook(cwd = process.cwd()) {
|
|
424
|
+
const pkg = readPackageJsonSafe(join(cwd, "package.json"));
|
|
425
|
+
if (!pkg) return true;
|
|
426
|
+
const existing = pkg.parsed.scripts?.prepare;
|
|
427
|
+
return typeof existing === "string" && existing.includes("skilld");
|
|
428
|
+
}
|
|
429
|
+
/**
|
|
502
430
|
* Prompt to add `skilld prepare` to package.json "prepare" script.
|
|
503
431
|
* In non-interactive environments, falls back to an info log.
|
|
504
432
|
* Returns true if the hook was added or already present.
|
|
505
433
|
*/
|
|
506
434
|
async function suggestPrepareHook(cwd = process.cwd()) {
|
|
507
435
|
const pkgJsonPath = join(cwd, "package.json");
|
|
508
|
-
|
|
509
|
-
|
|
510
|
-
const rawExisting =
|
|
436
|
+
const pkg = readPackageJsonSafe(pkgJsonPath);
|
|
437
|
+
if (!pkg) return false;
|
|
438
|
+
const rawExisting = pkg.parsed.scripts?.prepare;
|
|
511
439
|
const existing = typeof rawExisting === "string" ? rawExisting : void 0;
|
|
512
440
|
if (existing?.includes("skilld")) return true;
|
|
513
441
|
const prepareCmd = buildPrepareScript(existing);
|
|
@@ -533,20 +461,21 @@ async function suggestPrepareHook(cwd = process.cwd()) {
|
|
|
533
461
|
* Build the full prepare script value, safely appending to any existing command.
|
|
534
462
|
*/
|
|
535
463
|
function buildPrepareScript(existing) {
|
|
536
|
-
|
|
464
|
+
const cmd = "skilld prepare || true";
|
|
465
|
+
if (!existing || !existing.trim()) return cmd;
|
|
537
466
|
const cleaned = existing.trim().replace(/[&|;]+\s*$/, "").trim();
|
|
538
|
-
if (!cleaned) return
|
|
539
|
-
return `${cleaned} &&
|
|
467
|
+
if (!cleaned) return cmd;
|
|
468
|
+
return `${cleaned} && (${cmd})`;
|
|
540
469
|
}
|
|
541
470
|
function getRepoHint(name, cwd) {
|
|
542
|
-
const
|
|
543
|
-
if (!
|
|
544
|
-
const pkg =
|
|
471
|
+
const result = readPackageJsonSafe(join(cwd, "node_modules", name, "package.json"));
|
|
472
|
+
if (!result) return void 0;
|
|
473
|
+
const pkg = result.parsed;
|
|
545
474
|
const url = typeof pkg.repository === "string" ? pkg.repository : pkg.repository?.url;
|
|
546
475
|
if (!url) return void 0;
|
|
547
476
|
return url.replace(/^git\+/, "").replace(/\.git$/, "").replace(/^git:\/\//, "https://").replace(/^ssh:\/\/git@github\.com/, "https://github.com").replace(/^https?:\/\/(www\.)?github\.com\//, "");
|
|
548
477
|
}
|
|
549
478
|
//#endregion
|
|
550
|
-
export {
|
|
479
|
+
export { unregisterProject as A, version as C, hasConfig as D, hasCompletedWizard as E, readConfig as O, suggestPrepareHook as S, getRegisteredProjects as T, promptForAgent as _, formatStatus as a, resolveAgent as b, getRepoHint as c, hasPrepareHook as d, introLine as f, pickModel as g, menuLoop as h, buildPrepareScript as i, updateConfig as j, registerProject as k, groupModelsByProvider as l, isRunningInsideAgent as m, NO_MODELS_MESSAGE as n, getInstalledGenerators as o, isInteractive as p, OAUTH_NOTE as r, getLastSynced as s, MenuCancel as t, guard as u, relativeTime as v, defaultFeatures as w, sharedArgs as x, requireInteractive as y };
|
|
551
480
|
|
|
552
481
|
//# sourceMappingURL=cli-helpers.mjs.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"cli-helpers.mjs","names":["dirname","resolve","agents"],"sources":["../../src/core/config.ts","../../src/core/package-json.ts","../../src/version.ts","../../src/cli-helpers.ts"],"sourcesContent":["import type { OptimizeModel } from '../agent/index.ts'\nimport { existsSync, mkdirSync, readFileSync, writeFileSync } from 'node:fs'\nimport { homedir } from 'node:os'\nimport { join } from 'pathe'\nimport { yamlEscape, yamlParseKV, yamlUnescape } from './yaml.ts'\n\nexport interface FeaturesConfig {\n search: boolean\n issues: boolean\n discussions: boolean\n releases: boolean\n}\n\nexport const defaultFeatures: FeaturesConfig = {\n search: true,\n issues: true,\n discussions: true,\n releases: true,\n}\n\nexport interface SkilldConfig {\n model?: OptimizeModel\n agent?: string\n features?: FeaturesConfig\n projects?: string[]\n skipLlm?: boolean\n}\n\nconst CONFIG_DIR = join(homedir(), '.skilld')\nconst CONFIG_PATH = join(CONFIG_DIR, 'config.yaml')\n\nexport function hasConfig(): boolean {\n return existsSync(CONFIG_PATH)\n}\n\n/** Whether the first-run wizard has been completed (not just agent selection) */\nexport function hasCompletedWizard(): boolean {\n if (!existsSync(CONFIG_PATH))\n return false\n const config = readConfig()\n return config.features !== undefined || config.model !== undefined || config.skipLlm !== undefined\n}\n\nexport function readConfig(): SkilldConfig {\n if (!existsSync(CONFIG_PATH))\n return {}\n\n const content = readFileSync(CONFIG_PATH, 'utf-8')\n const config: SkilldConfig = {}\n let inBlock: 'projects' | 'features' | null = null\n const projects: string[] = []\n const features: Partial<FeaturesConfig> = {}\n\n for (const line of content.split('\\n')) {\n if (line.startsWith('projects:')) {\n inBlock = 'projects'\n continue\n }\n if (line.startsWith('features:')) {\n inBlock = 'features'\n continue\n }\n if (inBlock === 'projects') {\n if (line.startsWith(' - ')) {\n projects.push(yamlUnescape(line.slice(4)))\n continue\n }\n inBlock = null\n }\n if (inBlock === 'features') {\n const m = line.match(/^ {2}(\\w+):\\s*(.+)/)\n if (m) {\n const key = m[1] as keyof FeaturesConfig\n if (key in defaultFeatures)\n features[key] = m[2] === 'true'\n continue\n }\n inBlock = null\n }\n const kv = yamlParseKV(line)\n if (!kv)\n continue\n const [key, value] = kv\n if (key === 'model' && value)\n config.model = value as OptimizeModel\n if (key === 'agent' && value)\n config.agent = value\n if (key === 'skipLlm')\n config.skipLlm = value === 'true'\n }\n\n if (projects.length > 0)\n config.projects = projects\n if (Object.keys(features).length > 0)\n config.features = { ...defaultFeatures, ...features }\n return config\n}\n\nexport function writeConfig(config: SkilldConfig): void {\n mkdirSync(CONFIG_DIR, { recursive: true, mode: 0o700 })\n\n let yaml = ''\n if (config.model)\n yaml += `model: ${config.model}\\n`\n if (config.agent)\n yaml += `agent: ${config.agent}\\n`\n if (config.skipLlm)\n yaml += `skipLlm: true\\n`\n if (config.features) {\n yaml += 'features:\\n'\n for (const [k, v] of Object.entries(config.features)) {\n yaml += ` ${k}: ${v}\\n`\n }\n }\n if (config.projects?.length) {\n yaml += 'projects:\\n'\n for (const p of config.projects) {\n yaml += ` - ${yamlEscape(p)}\\n`\n }\n }\n\n writeFileSync(CONFIG_PATH, yaml, { mode: 0o600 })\n}\n\nexport function updateConfig(updates: Partial<SkilldConfig>): void {\n const config = readConfig()\n writeConfig({ ...config, ...updates })\n}\n\nexport function registerProject(projectPath: string): void {\n const config = readConfig()\n const projects = new Set(config.projects || [])\n projects.add(projectPath)\n writeConfig({ ...config, projects: [...projects] })\n}\n\nexport function unregisterProject(projectPath: string): void {\n const config = readConfig()\n const projects = (config.projects || []).filter(p => p !== projectPath)\n writeConfig({ ...config, projects })\n}\n\nexport function getRegisteredProjects(): string[] {\n return readConfig().projects || []\n}\n","import { 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/**\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 * Remove a value at a JSON path, preserving all surrounding formatting.\n */\nexport function removeJsonProperty(raw: string, path: (string | number)[]): string {\n const edits = modify(raw, path, undefined, {})\n return applyEdits(raw, edits)\n}\n\n/**\n * Read a package.json, apply an edit function, and write it back.\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 = readFileSync(pkgPath, 'utf-8')\n const pkg = JSON.parse(raw)\n const result = editFn(raw, pkg)\n if (result === null)\n return false\n writeFileSync(pkgPath, result)\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","import { readFileSync } from 'node:fs'\nimport { dirname, resolve } from 'node:path'\nimport { fileURLToPath } from 'node:url'\n\n// Walk up from current file to find package.json (works in both src/ and dist/_chunks/)\nfunction findPackageJson(): string {\n let dir = dirname(fileURLToPath(import.meta.url))\n for (let i = 0; i < 5; i++) {\n const candidate = resolve(dir, 'package.json')\n try {\n const content = readFileSync(candidate, 'utf8')\n if (content)\n return content\n }\n catch {}\n dir = resolve(dir, '..')\n }\n return '{\"version\":\"0.0.0\"}'\n}\n\nexport const version: string = JSON.parse(findPackageJson()).version\n","/**\n * Shared CLI helpers used by subcommand definitions and the main CLI entry.\n * Extracted to avoid circular deps between cli.ts and commands/*.ts.\n */\n\nimport type { AgentType, OptimizeModel } from './agent/index.ts'\nimport type { ProjectState } from './core/skills.ts'\nimport { existsSync, readFileSync } from 'node:fs'\nimport * as p from '@clack/prompts'\nimport { parseTree } from 'jsonc-parser'\nimport { join } from 'pathe'\nimport { detectCurrentAgent } from 'unagent/env'\nimport { agents, detectInstalledAgents, detectProjectAgents, detectTargetAgent, getAgentVersion, getModelName } from './agent/index.ts'\nimport { readConfig, updateConfig } from './core/config.ts'\nimport { editJsonProperty, patchPackageJson } from './core/package-json.ts'\nimport { version } from './version.ts'\n\nexport type { AgentType, OptimizeModel }\n\nexport interface IntroOptions {\n state: ProjectState\n /** Installed CLIs that can serve as enhancement models */\n generators?: Array<{ name: string, version: string }>\n /** Configured enhancement model ID */\n modelId?: string\n /** Resolved target agent ID */\n agentId?: string\n}\n\nexport const sharedArgs = {\n global: {\n type: 'boolean' as const,\n alias: 'g',\n description: 'Install globally to ~/<agent>/skills',\n default: false,\n },\n agent: {\n type: 'enum' as const,\n options: Object.keys(agents),\n alias: 'a',\n description: 'Target agent — where skills are installed',\n },\n model: {\n type: 'string' as const,\n alias: 'm',\n description: 'Enhancement model for SKILL.md generation',\n valueHint: 'id',\n },\n yes: {\n type: 'boolean' as const,\n alias: 'y',\n description: 'Skip prompts, use defaults',\n default: false,\n },\n force: {\n type: 'boolean' as const,\n alias: 'f',\n description: 'Ignore all caches, re-fetch docs and regenerate',\n default: false,\n },\n debug: {\n type: 'boolean' as const,\n description: 'Save raw enhancement output to logs/ for each section',\n default: false,\n },\n}\n\n// ── Menu loop utility ─────────────────────────────────────────────────\n\n/** Thrown when a clack prompt is cancelled inside a menuLoop handler */\nexport class MenuCancel extends Error { override name = 'MenuCancel' }\n\n/** Assert a clack prompt result is not cancelled. Throws MenuCancel if cancelled. */\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\n/**\n * Run a select menu in a loop with automatic back-navigation.\n *\n * - Cancel (Escape) at the menu itself → exits (returns)\n * - Cancel inside a handler (via guard()) → caught, loops back to menu\n * - Handler returns truthy → exits (returns)\n * - Handler returns void/false → loops back to menu\n *\n * Options are rebuilt each iteration so hints stay fresh after changes.\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 /** Use fuzzy-searchable autocomplete instead of static select */\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\n/** Check if we're running inside an AI coding agent */\nexport function isRunningInsideAgent(): boolean {\n return !!detectCurrentAgent()\n}\n\n/** Check if the current environment supports interactive prompts */\nexport function isInteractive(): boolean {\n if (isRunningInsideAgent())\n return false\n if (process.env.CI)\n return false\n if (!process.stdout.isTTY)\n return false\n return true\n}\n\n/** Exit with error if interactive terminal is required but unavailable */\nexport function requireInteractive(command: string): void {\n if (!isInteractive()) {\n console.error(`Error: \\`skilld ${command}\\` requires an interactive terminal`)\n process.exit(1)\n }\n}\n\n/** Resolve agent from flags/cwd/config. cwd is source of truth over config. */\nexport function resolveAgent(agentFlag?: string): AgentType | 'none' | null {\n if (process.env.SKILLD_NO_AGENT)\n return null\n return (agentFlag as AgentType | undefined)\n ?? detectTargetAgent()\n ?? (readConfig().agent as AgentType | undefined)\n ?? null\n}\n\nlet _warnedNoAgent = false\nfunction warnNoAgent(): void {\n if (_warnedNoAgent)\n return\n _warnedNoAgent = true\n p.log.warn('No target agent detected — falling back to prompt-only mode.\\n Use --agent <name> to specify, or run `skilld config` to set a default.')\n}\n\n/** Prompt user to pick an agent when auto-detection fails */\nexport async function promptForAgent(): Promise<AgentType | 'none' | null> {\n const noAgent = !!process.env.SKILLD_NO_AGENT\n const installed = noAgent ? [] : detectInstalledAgents()\n const projectMatches = noAgent ? [] : detectProjectAgents()\n\n // Non-interactive: auto-select sole installed agent or fall back to prompt-only\n if (!isInteractive()) {\n if (installed.length === 1) {\n updateConfig({ agent: installed[0] })\n return installed[0]!\n }\n warnNoAgent()\n return 'none'\n }\n\n // Brief context before asking about agents\n p.log.info(\n `Skilld generates reference cards from package docs so your AI agent\\n`\n + ` always has accurate APIs for your exact dependency versions.`,\n )\n\n // Build options: prefer project-matched agents, then installed, then all\n const candidateIds = projectMatches.length > 0\n ? projectMatches\n : installed.length > 0\n ? installed\n : Object.keys(agents) as AgentType[]\n\n // Agents that also read .claude/skills/\n const sharedAgents = new Set(\n Object.entries(agents)\n .filter(([, a]) => a.additionalSkillsDirs.some(d => d.includes('.claude/skills')))\n .map(([id]) => id),\n )\n\n // Group: agents that share skills vs agents with their own directory\n const sharedIds = candidateIds.filter(id => id === 'claude-code' || sharedAgents.has(id))\n const isolatedIds = candidateIds.filter(id => id !== 'claude-code' && !sharedAgents.has(id))\n\n const options: Array<{ label: string, value: AgentType | 'none', hint?: string }> = []\n\n // Show shared-compatible agents first\n if (sharedIds.length > 0 && isolatedIds.length > 0) {\n for (const id of sharedIds) {\n const a = agents[id]\n const hint = id === 'claude-code'\n ? `skills shared with ${sharedIds.length - 1} other agents`\n : `skills shared with Claude Code and others`\n options.push({ label: a.displayName, value: id as AgentType, hint })\n }\n }\n\n // Agents with isolated skill dirs\n const isolatedAgentIds = new Set(\n Object.entries(agents)\n .filter(([, a]) => a.additionalSkillsDirs.length === 0)\n .map(([id]) => id),\n )\n\n for (const id of (sharedIds.length > 0 && isolatedIds.length > 0 ? isolatedIds : candidateIds)) {\n if (options.some(o => o.value === id))\n continue\n const a = agents[id]\n const hint = sharedAgents.has(id) && id !== 'claude-code'\n ? 'skills shared with Claude Code and others'\n : isolatedAgentIds.has(id)\n ? 'skills only visible to this agent'\n : undefined\n options.push({ label: a.displayName, value: id as AgentType, hint })\n }\n\n options.push({ label: 'No agent', value: 'none', hint: 'export as standalone files for any AI' })\n\n if (!_warnedNoAgent) {\n _warnedNoAgent = true\n const hint = projectMatches.length > 1\n ? `Multiple agent directories found: ${projectMatches.map(t => agents[t].displayName).join(', ')}`\n : installed.length > 0\n ? `Found ${installed.map(t => agents[t].displayName).join(', ')} but couldn't determine which to use`\n : 'No agents auto-detected'\n const crossNote = sharedIds.length > 1\n ? `\\n \\x1B[90mTip: Picking Claude Code shares skills with ${sharedIds.filter(id => id !== 'claude-code').map(id => agents[id].displayName).join(', ')} automatically.\\x1B[0m`\n : ''\n p.log.warn(`${hint}\\n Pick the agent you actively code with.${crossNote}`)\n }\n\n const choice = await p.select({\n message: 'Which AI coding agent do you use?',\n options,\n })\n\n if (p.isCancel(choice))\n return null\n\n if (choice === 'none')\n return 'none'\n\n // Save as default so they don't get asked again\n updateConfig({ agent: choice })\n p.log.success(`Target agent set to ${agents[choice].displayName}`)\n return choice\n}\n\n/** Get installed LLM generators with working CLIs (verified via --version) */\nexport function getInstalledGenerators(): Array<{ name: string, version: string }> {\n const installed = detectInstalledAgents()\n return installed\n .filter(id => agents[id].cli)\n .map((id) => {\n const ver = getAgentVersion(id)\n return ver ? { name: agents[id].displayName, version: ver } : null\n })\n .filter((a): a is { name: string, version: string } => a !== null)\n}\n\nexport function relativeTime(date: Date): string {\n const now = Date.now()\n const diff = now - date.getTime()\n const mins = Math.floor(diff / 60000)\n const hours = Math.floor(diff / 3600000)\n const days = Math.floor(diff / 86400000)\n if (mins < 1)\n return 'just now'\n if (mins < 60)\n return `${mins}m ago`\n if (hours < 24)\n return `${hours}h ago`\n return `${days}d ago`\n}\n\nexport function getLastSynced(state: ProjectState): string | null {\n let latest: Date | null = null\n for (const skill of state.skills) {\n if (skill.info?.syncedAt) {\n const d = new Date(skill.info.syncedAt)\n if (!latest || d > latest)\n latest = d\n }\n }\n return latest ? relativeTime(latest) : null\n}\n\nexport function introLine({ state, generators, modelId, agentId }: IntroOptions): string {\n const name = '\\x1B[1m\\x1B[35mskilld\\x1B[0m'\n const ver = `\\x1B[90mv${version}\\x1B[0m`\n const lastSynced = getLastSynced(state)\n const synced = lastSynced ? ` · \\x1B[90msynced ${lastSynced}\\x1B[0m` : ''\n\n // Status line: enhancement model → target agent\n const parts: string[] = []\n if (modelId)\n parts.push(getModelName(modelId as any))\n else if (generators?.length)\n parts.push(generators.map(g => `${g.name} v${g.version}`).join(', '))\n if (agentId && agents[agentId as AgentType])\n parts.push(agents[agentId as AgentType].displayName)\n const statusLine = parts.length > 0\n ? `\\n\\x1B[90m↳ ${parts.join(' → ')}\\x1B[0m`\n : ''\n\n return `${name} ${ver}${synced}${statusLine}`\n}\n\nexport function formatStatus(synced: number, outdated: number): string {\n const parts: string[] = []\n if (synced > 0)\n parts.push(`\\x1B[32m${synced} synced\\x1B[0m`)\n if (outdated > 0)\n parts.push(`\\x1B[33m${outdated} outdated\\x1B[0m`)\n return `Skills: ${parts.join(' · ')}`\n}\n\n// ── Shared UI constants ───────────────────────────────────────────────\n\nexport const OAUTH_NOTE\n = 'Use an existing subscription (Claude Pro, ChatGPT Plus, Gemini)\\n'\n + 'without an API key. You authenticate directly with the provider\\n'\n + 'in your browser - no data leaves your machine.\\n'\n + '\\n'\n + 'A refresh token is stored locally at ~/.skilld/pi-ai-auth.json\\n'\n + 'and used to call the provider API directly from your computer.\\n'\n + '\\x1B[90mOAuth handled by pi-ai, an open-source local client library:\\n'\n + 'https://github.com/badlogic/pi-mono\\x1B[0m'\n\nexport const NO_MODELS_MESSAGE = 'No enhancement models detected.\\n'\n + ' \\x1B[90mSkills work fine without this - you get raw docs, issues, and types.\\n'\n + ' Enhancement compresses them into a concise cheat sheet with gotchas.\\x1B[0m\\n'\n + '\\n'\n + ' To connect a model (optional):\\n'\n + ' 1. Connect a subscription via OAuth below (Claude Pro, ChatGPT Plus, Copilot, Gemini)\\n'\n + ' 2. Set an env var: ANTHROPIC_API_KEY, GEMINI_API_KEY, or OPENAI_API_KEY\\n'\n + ' 3. Install a CLI tool: \\x1B[36mclaude\\x1B[0m, \\x1B[36mgemini\\x1B[0m, or \\x1B[36mcodex\\x1B[0m (restart wizard after)'\n\n/** Group models by vendor for provider→model selection. Uses vendorGroup to merge CLI and API entries under one heading. */\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 /** Extra options prepended (e.g. Auto, Connect OAuth) */\n before?: Array<{ label: string, value: string, hint?: string }>\n /** Extra options appended (e.g. Skip) */\n after?: Array<{ label: string, value: string, hint?: string }>\n}\n\n/**\n * Smart provider→model picker. Skips the provider step when there's only 1 provider.\n * Returns the selected model value, or a sentinel string from before/after options.\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 // Single provider → skip provider step, show models directly\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 // Multiple providers or has before options - two-step\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 // Check if it's a sentinel from before/after\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 // Drill into provider's models\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\n/**\n * Prompt to add `skilld prepare` to package.json \"prepare\" script.\n * In non-interactive environments, falls back to an info log.\n * Returns true if the hook was added or already present.\n */\nexport async function suggestPrepareHook(cwd: string = process.cwd()): Promise<boolean> {\n const pkgJsonPath = join(cwd, 'package.json')\n if (!existsSync(pkgJsonPath))\n return false\n\n const raw = readFileSync(pkgJsonPath, 'utf-8')\n const pkgJson = JSON.parse(raw)\n const rawExisting = pkgJson.scripts?.prepare\n const existing: string | undefined = typeof rawExisting === 'string' ? rawExisting : undefined\n\n if (existing?.includes('skilld'))\n return true\n\n const prepareCmd = buildPrepareScript(existing)\n\n if (!isInteractive()) {\n p.log.info(\n `\\x1B[90mAdd to package.json scripts:\\n`\n + ` \\x1B[36m\"prepare\": \"${prepareCmd}\"\\x1B[0m\\n`\n + ` \\x1B[90mRestores references and shipped skills on install.\\x1B[0m`,\n )\n return false\n }\n\n const confirmed = await p.confirm({\n message: `Add \\x1B[36m\"prepare\": \"${prepareCmd}\"\\x1B[0m to package.json?`,\n initialValue: true,\n })\n if (p.isCancel(confirmed) || !confirmed)\n return false\n\n patchPackageJson(pkgJsonPath, (content) => {\n const tree = parseTree(content)\n const hasScripts = tree?.children?.some(c =>\n c.type === 'property' && c.children?.[0]?.value === 'scripts',\n )\n\n let patched = content\n if (!hasScripts)\n patched = editJsonProperty(patched, ['scripts'], {})\n\n return editJsonProperty(patched, ['scripts', 'prepare'], prepareCmd)\n })\n p.log.success('Added \\x1B[36mskilld prepare\\x1B[0m to package.json')\n return true\n}\n\n/**\n * Build the full prepare script value, safely appending to any existing command.\n */\nexport function buildPrepareScript(existing: string | undefined): string {\n if (!existing || !existing.trim())\n return 'skilld prepare'\n\n const trimmed = existing.trim()\n\n // Strip trailing && or ; that would leave a dangling operator\n const cleaned = trimmed.replace(/[&|;]+\\s*$/, '').trim()\n if (!cleaned)\n return 'skilld prepare'\n\n return `${cleaned} && skilld prepare`\n}\n\nexport function getRepoHint(name: string, cwd: string): string | undefined {\n const pkgJsonPath = join(cwd, 'node_modules', name, 'package.json')\n if (!existsSync(pkgJsonPath))\n return undefined\n const pkg = JSON.parse(readFileSync(pkgJsonPath, 'utf-8'))\n const url = typeof pkg.repository === 'string'\n ? pkg.repository\n : pkg.repository?.url\n if (!url)\n return undefined\n return url\n .replace(/^git\\+/, '')\n .replace(/\\.git$/, '')\n .replace(/^git:\\/\\//, 'https://')\n .replace(/^ssh:\\/\\/git@github\\.com/, 'https://github.com')\n .replace(/^https?:\\/\\/(www\\.)?github\\.com\\//, '')\n}\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"cli-helpers.mjs","names":["dirname","resolve","agents"],"sources":["../../src/core/config.ts","../../src/version.ts","../../src/cli-helpers.ts"],"sourcesContent":["import type { OptimizeModel } from '../agent/index.ts'\nimport { existsSync, mkdirSync, readFileSync, writeFileSync } from 'node:fs'\nimport { homedir } from 'node:os'\nimport { join } from 'pathe'\nimport { yamlEscape, yamlParseKV, yamlUnescape } from './yaml.ts'\n\nexport interface FeaturesConfig {\n search: boolean\n issues: boolean\n discussions: boolean\n releases: boolean\n}\n\nexport const defaultFeatures: FeaturesConfig = {\n search: true,\n issues: true,\n discussions: true,\n releases: true,\n}\n\nexport interface SkilldConfig {\n model?: OptimizeModel\n agent?: string\n features?: FeaturesConfig\n projects?: string[]\n skipLlm?: boolean\n}\n\nconst CONFIG_DIR = join(homedir(), '.skilld')\nconst CONFIG_PATH = join(CONFIG_DIR, 'config.yaml')\n\nlet configCache: SkilldConfig | undefined\n\nexport function hasConfig(): boolean {\n return existsSync(CONFIG_PATH)\n}\n\n/** Whether the first-run wizard has been completed (not just agent selection) */\nexport function hasCompletedWizard(): boolean {\n if (!existsSync(CONFIG_PATH))\n return false\n const config = readConfig()\n return config.features !== undefined || config.model !== undefined || config.skipLlm !== undefined\n}\n\nexport function readConfig(): SkilldConfig {\n if (configCache) {\n return {\n ...configCache,\n features: configCache.features ? { ...configCache.features } : undefined,\n projects: configCache.projects ? [...configCache.projects] : undefined,\n }\n }\n if (!existsSync(CONFIG_PATH))\n return {}\n\n const content = readFileSync(CONFIG_PATH, 'utf-8')\n const config: SkilldConfig = {}\n let inBlock: 'projects' | 'features' | null = null\n const projects: string[] = []\n const features: Partial<FeaturesConfig> = {}\n\n for (const line of content.split('\\n')) {\n if (line.startsWith('projects:')) {\n inBlock = 'projects'\n continue\n }\n if (line.startsWith('features:')) {\n inBlock = 'features'\n continue\n }\n if (inBlock === 'projects') {\n if (line.startsWith(' - ')) {\n projects.push(yamlUnescape(line.slice(4)))\n continue\n }\n inBlock = null\n }\n if (inBlock === 'features') {\n const m = line.match(/^ {2}(\\w+):\\s*(.+)/)\n if (m) {\n const key = m[1] as keyof FeaturesConfig\n if (key in defaultFeatures)\n features[key] = m[2] === 'true'\n continue\n }\n inBlock = null\n }\n const kv = yamlParseKV(line)\n if (!kv)\n continue\n const [key, value] = kv\n if (key === 'model' && value)\n config.model = value as OptimizeModel\n if (key === 'agent' && value)\n config.agent = value\n if (key === 'skipLlm')\n config.skipLlm = value === 'true'\n }\n\n if (projects.length > 0)\n config.projects = projects\n if (Object.keys(features).length > 0)\n config.features = { ...defaultFeatures, ...features }\n configCache = config\n return config\n}\n\nexport function writeConfig(config: SkilldConfig): void {\n mkdirSync(CONFIG_DIR, { recursive: true, mode: 0o700 })\n\n let yaml = ''\n if (config.model)\n yaml += `model: ${config.model}\\n`\n if (config.agent)\n yaml += `agent: ${config.agent}\\n`\n if (config.skipLlm)\n yaml += `skipLlm: true\\n`\n if (config.features) {\n yaml += 'features:\\n'\n for (const [k, v] of Object.entries(config.features)) {\n yaml += ` ${k}: ${v}\\n`\n }\n }\n if (config.projects?.length) {\n yaml += 'projects:\\n'\n for (const p of config.projects) {\n yaml += ` - ${yamlEscape(p)}\\n`\n }\n }\n\n writeFileSync(CONFIG_PATH, yaml, { mode: 0o600 })\n configCache = undefined\n}\n\nexport function updateConfig(updates: Partial<SkilldConfig>): void {\n const config = readConfig()\n writeConfig({ ...config, ...updates })\n}\n\nexport function registerProject(projectPath: string): void {\n const config = readConfig()\n const projects = new Set(config.projects || [])\n projects.add(projectPath)\n writeConfig({ ...config, projects: [...projects] })\n}\n\nexport function unregisterProject(projectPath: string): void {\n const config = readConfig()\n const projects = (config.projects || []).filter(p => p !== projectPath)\n writeConfig({ ...config, projects })\n}\n\nexport function getRegisteredProjects(): string[] {\n return readConfig().projects || []\n}\n","import { readFileSync } from 'node:fs'\nimport { dirname, resolve } from 'node:path'\nimport { fileURLToPath } from 'node:url'\n\n// Walk up from current file to find package.json (works in both src/ and dist/_chunks/)\nfunction findPackageJson(): string {\n let dir = dirname(fileURLToPath(import.meta.url))\n for (let i = 0; i < 5; i++) {\n const candidate = resolve(dir, 'package.json')\n try {\n const content = readFileSync(candidate, 'utf8')\n if (content)\n return content\n }\n catch {}\n dir = resolve(dir, '..')\n }\n return '{\"version\":\"0.0.0\"}'\n}\n\nexport const version: string = JSON.parse(findPackageJson()).version\n","/**\n * Shared CLI helpers used by subcommand definitions and the main CLI entry.\n * Extracted to avoid circular deps between cli.ts and commands/*.ts.\n */\n\nimport type { AgentType, OptimizeModel } from './agent/index.ts'\nimport type { ProjectState } from './core/skills.ts'\nimport * as p from '@clack/prompts'\nimport { parseTree } from 'jsonc-parser'\nimport { join } from 'pathe'\nimport { detectCurrentAgent } from 'unagent/env'\nimport { agents, detectInstalledAgents, detectProjectAgents, detectTargetAgent, getAgentVersion, getModelName } from './agent/index.ts'\nimport { readConfig, updateConfig } from './core/config.ts'\nimport { editJsonProperty, patchPackageJson, readPackageJsonSafe } from './core/package-json.ts'\nimport { version } from './version.ts'\n\nexport type { AgentType, OptimizeModel }\n\nexport interface IntroOptions {\n state: ProjectState\n /** Installed CLIs that can serve as enhancement models */\n generators?: Array<{ name: string, version: string }>\n /** Configured enhancement model ID */\n modelId?: string\n /** Resolved target agent ID */\n agentId?: string\n}\n\nexport const sharedArgs = {\n global: {\n type: 'boolean' as const,\n alias: 'g',\n description: 'Install globally to ~/<agent>/skills',\n default: false,\n },\n agent: {\n type: 'enum' as const,\n options: Object.keys(agents),\n alias: 'a',\n description: 'Target agent — where skills are installed',\n },\n model: {\n type: 'string' as const,\n alias: 'm',\n description: 'Enhancement model for SKILL.md generation',\n valueHint: 'id',\n },\n yes: {\n type: 'boolean' as const,\n alias: 'y',\n description: 'Skip prompts, use defaults',\n default: false,\n },\n force: {\n type: 'boolean' as const,\n alias: 'f',\n description: 'Ignore all caches, re-fetch docs and regenerate',\n default: false,\n },\n debug: {\n type: 'boolean' as const,\n description: 'Save raw enhancement output to logs/ for each section',\n default: false,\n },\n}\n\n// ── Menu loop utility ─────────────────────────────────────────────────\n\n/** Thrown when a clack prompt is cancelled inside a menuLoop handler */\nexport class MenuCancel extends Error { override name = 'MenuCancel' }\n\n/** Assert a clack prompt result is not cancelled. Throws MenuCancel if cancelled. */\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\n/**\n * Run a select menu in a loop with automatic back-navigation.\n *\n * - Cancel (Escape) at the menu itself → exits (returns)\n * - Cancel inside a handler (via guard()) → caught, loops back to menu\n * - Handler returns truthy → exits (returns)\n * - Handler returns void/false → loops back to menu\n *\n * Options are rebuilt each iteration so hints stay fresh after changes.\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 /** Use fuzzy-searchable autocomplete instead of static select */\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\n/** Check if we're running inside an AI coding agent */\nexport function isRunningInsideAgent(): boolean {\n return !!detectCurrentAgent()\n}\n\n/** Check if the current environment supports interactive prompts */\nexport function isInteractive(): boolean {\n if (isRunningInsideAgent())\n return false\n if (process.env.CI)\n return false\n if (!process.stdout.isTTY)\n return false\n return true\n}\n\n/** Exit with error if interactive terminal is required but unavailable */\nexport function requireInteractive(command: string): void {\n if (!isInteractive()) {\n console.error(`Error: \\`skilld ${command}\\` requires an interactive terminal`)\n process.exit(1)\n }\n}\n\n/** Resolve agent from flags/cwd/config. cwd is source of truth over config. */\nexport function resolveAgent(agentFlag?: string): AgentType | 'none' | null {\n if (process.env.SKILLD_NO_AGENT)\n return null\n return (agentFlag as AgentType | undefined)\n ?? detectTargetAgent()\n ?? (readConfig().agent as AgentType | undefined)\n ?? null\n}\n\nlet _warnedNoAgent = false\nfunction warnNoAgent(): void {\n if (_warnedNoAgent)\n return\n _warnedNoAgent = true\n p.log.warn('No target agent detected — falling back to prompt-only mode.\\n Use --agent <name> to specify, or run `skilld config` to set a default.')\n}\n\n/** Prompt user to pick an agent when auto-detection fails */\nexport async function promptForAgent(): Promise<AgentType | 'none' | null> {\n const noAgent = !!process.env.SKILLD_NO_AGENT\n const installed = noAgent ? [] : detectInstalledAgents()\n const projectMatches = noAgent ? [] : detectProjectAgents()\n\n // Non-interactive: auto-select sole installed agent or fall back to prompt-only\n if (!isInteractive()) {\n if (installed.length === 1) {\n updateConfig({ agent: installed[0] })\n return installed[0]!\n }\n warnNoAgent()\n return 'none'\n }\n\n // Brief context before asking about agents\n p.log.info(\n `Skilld generates reference cards from package docs so your AI agent\\n`\n + ` always has accurate APIs for your exact dependency versions.`,\n )\n\n // Build options: prefer project-matched agents, then installed, then all\n const candidateIds = projectMatches.length > 0\n ? projectMatches\n : installed.length > 0\n ? installed\n : Object.keys(agents) as AgentType[]\n\n // Agents that also read .claude/skills/\n const sharedAgents = new Set(\n Object.entries(agents)\n .filter(([, a]) => a.additionalSkillsDirs.some(d => d.includes('.claude/skills')))\n .map(([id]) => id),\n )\n\n // Group: agents that share skills vs agents with their own directory\n const sharedIds = candidateIds.filter(id => id === 'claude-code' || sharedAgents.has(id))\n const isolatedIds = candidateIds.filter(id => id !== 'claude-code' && !sharedAgents.has(id))\n\n const options: Array<{ label: string, value: AgentType | 'none', hint?: string }> = []\n\n // Show shared-compatible agents first\n if (sharedIds.length > 0 && isolatedIds.length > 0) {\n for (const id of sharedIds) {\n const a = agents[id]\n const hint = id === 'claude-code'\n ? `skills shared with ${sharedIds.length - 1} other agents`\n : `skills shared with Claude Code and others`\n options.push({ label: a.displayName, value: id as AgentType, hint })\n }\n }\n\n // Agents with isolated skill dirs\n const isolatedAgentIds = new Set(\n Object.entries(agents)\n .filter(([, a]) => a.additionalSkillsDirs.length === 0)\n .map(([id]) => id),\n )\n\n for (const id of (sharedIds.length > 0 && isolatedIds.length > 0 ? isolatedIds : candidateIds)) {\n if (options.some(o => o.value === id))\n continue\n const a = agents[id]\n const hint = sharedAgents.has(id) && id !== 'claude-code'\n ? 'skills shared with Claude Code and others'\n : isolatedAgentIds.has(id)\n ? 'skills only visible to this agent'\n : undefined\n options.push({ label: a.displayName, value: id as AgentType, hint })\n }\n\n options.push({ label: 'No agent', value: 'none', hint: 'export as standalone files for any AI' })\n\n if (!_warnedNoAgent) {\n _warnedNoAgent = true\n const hint = projectMatches.length > 1\n ? `Multiple agent directories found: ${projectMatches.map(t => agents[t].displayName).join(', ')}`\n : installed.length > 0\n ? `Found ${installed.map(t => agents[t].displayName).join(', ')} but couldn't determine which to use`\n : 'No agents auto-detected'\n const crossNote = sharedIds.length > 1\n ? `\\n \\x1B[90mTip: Picking Claude Code shares skills with ${sharedIds.filter(id => id !== 'claude-code').map(id => agents[id].displayName).join(', ')} automatically.\\x1B[0m`\n : ''\n p.log.warn(`${hint}\\n Pick the agent you actively code with.${crossNote}`)\n }\n\n const choice = await p.select({\n message: 'Which AI coding agent do you use?',\n options,\n })\n\n if (p.isCancel(choice))\n return null\n\n if (choice === 'none')\n return 'none'\n\n // Save as default so they don't get asked again\n updateConfig({ agent: choice })\n p.log.success(`Target agent set to ${agents[choice].displayName}`)\n return choice\n}\n\n/** Get installed LLM generators with working CLIs (verified via --version) */\nexport function getInstalledGenerators(): Array<{ name: string, version: string }> {\n const installed = detectInstalledAgents()\n return installed\n .filter(id => agents[id].cli)\n .map((id) => {\n const ver = getAgentVersion(id)\n return ver ? { name: agents[id].displayName, version: ver } : null\n })\n .filter((a): a is { name: string, version: string } => a !== null)\n}\n\nexport function relativeTime(date: Date): string {\n const now = Date.now()\n const diff = now - date.getTime()\n const mins = Math.floor(diff / 60000)\n const hours = Math.floor(diff / 3600000)\n const days = Math.floor(diff / 86400000)\n if (mins < 1)\n return 'just now'\n if (mins < 60)\n return `${mins}m ago`\n if (hours < 24)\n return `${hours}h ago`\n return `${days}d ago`\n}\n\nexport function getLastSynced(state: ProjectState): string | null {\n let latest: Date | null = null\n for (const skill of state.skills) {\n if (skill.info?.syncedAt) {\n const d = new Date(skill.info.syncedAt)\n if (!latest || d > latest)\n latest = d\n }\n }\n return latest ? relativeTime(latest) : null\n}\n\nexport function introLine({ state, generators, modelId, agentId }: IntroOptions): string {\n const name = '\\x1B[1m\\x1B[35mskilld\\x1B[0m'\n const ver = `\\x1B[90mv${version}\\x1B[0m`\n const lastSynced = getLastSynced(state)\n const synced = lastSynced ? ` · \\x1B[90msynced ${lastSynced}\\x1B[0m` : ''\n\n // Status line: enhancement model → target agent\n const parts: string[] = []\n if (modelId)\n parts.push(getModelName(modelId as any))\n else if (generators?.length)\n parts.push(generators.map(g => `${g.name} v${g.version}`).join(', '))\n if (agentId && agents[agentId as AgentType])\n parts.push(agents[agentId as AgentType].displayName)\n const statusLine = parts.length > 0\n ? `\\n\\x1B[90m↳ ${parts.join(' → ')}\\x1B[0m`\n : ''\n\n return `${name} ${ver}${synced}${statusLine}`\n}\n\nexport function formatStatus(synced: number, outdated: number): string {\n const parts: string[] = []\n if (synced > 0)\n parts.push(`\\x1B[32m${synced} synced\\x1B[0m`)\n if (outdated > 0)\n parts.push(`\\x1B[33m${outdated} outdated\\x1B[0m`)\n return `Skills: ${parts.join(' · ')}`\n}\n\n// ── Shared UI constants ───────────────────────────────────────────────\n\nexport const OAUTH_NOTE\n = 'Use an existing subscription (Claude Pro, ChatGPT Plus, Gemini)\\n'\n + 'without an API key. You authenticate directly with the provider\\n'\n + 'in your browser - no data leaves your machine.\\n'\n + '\\n'\n + 'A refresh token is stored locally at ~/.skilld/pi-ai-auth.json\\n'\n + 'and used to call the provider API directly from your computer.\\n'\n + '\\x1B[90mOAuth handled by pi-ai, an open-source local client library:\\n'\n + 'https://github.com/badlogic/pi-mono\\x1B[0m'\n\nexport const NO_MODELS_MESSAGE = 'No enhancement models detected.\\n'\n + ' \\x1B[90mSkills work fine without this - you get raw docs, issues, and types.\\n'\n + ' Enhancement compresses them into a concise cheat sheet with gotchas.\\x1B[0m\\n'\n + '\\n'\n + ' To connect a model (optional):\\n'\n + ' 1. Connect a subscription via OAuth below (Claude Pro, ChatGPT Plus, Copilot, Gemini)\\n'\n + ' 2. Set an env var: ANTHROPIC_API_KEY, GEMINI_API_KEY, or OPENAI_API_KEY\\n'\n + ' 3. Install a CLI tool: \\x1B[36mclaude\\x1B[0m, \\x1B[36mgemini\\x1B[0m, or \\x1B[36mcodex\\x1B[0m (restart wizard after)'\n\n/** Group models by vendor for provider→model selection. Uses vendorGroup to merge CLI and API entries under one heading. */\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 /** Extra options prepended (e.g. Auto, Connect OAuth) */\n before?: Array<{ label: string, value: string, hint?: string }>\n /** Extra options appended (e.g. Skip) */\n after?: Array<{ label: string, value: string, hint?: string }>\n}\n\n/**\n * Smart provider→model picker. Skips the provider step when there's only 1 provider.\n * Returns the selected model value, or a sentinel string from before/after options.\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 // Single provider → skip provider step, show models directly\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 // Multiple providers or has before options - two-step\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 // Check if it's a sentinel from before/after\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 // Drill into provider's models\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\n/**\n * Check if the prepare hook is already installed in package.json.\n */\nexport function hasPrepareHook(cwd: string = process.cwd()): boolean {\n const pkg = readPackageJsonSafe(join(cwd, 'package.json'))\n if (!pkg)\n return true // no package.json means nothing to suggest\n const existing = (pkg.parsed.scripts as Record<string, unknown> | undefined)?.prepare\n return typeof existing === 'string' && existing.includes('skilld')\n}\n\n/**\n * Prompt to add `skilld prepare` to package.json \"prepare\" script.\n * In non-interactive environments, falls back to an info log.\n * Returns true if the hook was added or already present.\n */\nexport async function suggestPrepareHook(cwd: string = process.cwd()): Promise<boolean> {\n const pkgJsonPath = join(cwd, 'package.json')\n const pkg = readPackageJsonSafe(pkgJsonPath)\n if (!pkg)\n return false\n\n const rawExisting = (pkg.parsed.scripts as Record<string, unknown> | undefined)?.prepare\n const existing: string | undefined = typeof rawExisting === 'string' ? rawExisting : undefined\n\n if (existing?.includes('skilld'))\n return true\n\n const prepareCmd = buildPrepareScript(existing)\n\n if (!isInteractive()) {\n p.log.info(\n `\\x1B[90mAdd to package.json scripts:\\n`\n + ` \\x1B[36m\"prepare\": \"${prepareCmd}\"\\x1B[0m\\n`\n + ` \\x1B[90mRestores references and shipped skills on install.\\x1B[0m`,\n )\n return false\n }\n\n const confirmed = await p.confirm({\n message: `Add \\x1B[36m\"prepare\": \"${prepareCmd}\"\\x1B[0m to package.json?`,\n initialValue: true,\n })\n if (p.isCancel(confirmed) || !confirmed)\n return false\n\n patchPackageJson(pkgJsonPath, (content) => {\n const tree = parseTree(content)\n const hasScripts = tree?.children?.some(c =>\n c.type === 'property' && c.children?.[0]?.value === 'scripts',\n )\n\n let patched = content\n if (!hasScripts)\n patched = editJsonProperty(patched, ['scripts'], {})\n\n return editJsonProperty(patched, ['scripts', 'prepare'], prepareCmd)\n })\n p.log.success('Added \\x1B[36mskilld prepare\\x1B[0m to package.json')\n return true\n}\n\n/**\n * Build the full prepare script value, safely appending to any existing command.\n */\nexport function buildPrepareScript(existing: string | undefined): string {\n const cmd = 'skilld prepare || true'\n if (!existing || !existing.trim())\n return cmd\n\n const trimmed = existing.trim()\n\n // Strip trailing && or ; that would leave a dangling operator\n const cleaned = trimmed.replace(/[&|;]+\\s*$/, '').trim()\n if (!cleaned)\n return cmd\n\n return `${cleaned} && (${cmd})`\n}\n\nexport function getRepoHint(name: string, cwd: string): string | undefined {\n const result = readPackageJsonSafe(join(cwd, 'node_modules', name, 'package.json'))\n if (!result)\n return undefined\n const pkg = result.parsed as Record<string, any>\n const url = typeof pkg.repository === 'string'\n ? pkg.repository\n : pkg.repository?.url\n if (!url)\n return undefined\n return url\n .replace(/^git\\+/, '')\n .replace(/\\.git$/, '')\n .replace(/^git:\\/\\//, 'https://')\n .replace(/^ssh:\\/\\/git@github\\.com/, 'https://github.com')\n .replace(/^https?:\\/\\/(www\\.)?github\\.com\\//, '')\n}\n"],"mappings":"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"}
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
import "./agent.mjs";
|
|
2
|
+
import "./config.mjs";
|
|
3
|
+
import "./package-json.mjs";
|
|
4
|
+
import "./prepare.mjs";
|
|
5
|
+
import "./sanitize.mjs";
|
|
6
|
+
import "./cache.mjs";
|
|
7
|
+
import "./yaml.mjs";
|
|
8
|
+
import "./shared.mjs";
|
|
9
|
+
import "./detect.mjs";
|
|
10
|
+
import "./prompts.mjs";
|
|
11
|
+
import { S as suggestPrepareHook } from "./cli-helpers.mjs";
|
|
12
|
+
export { suggestPrepareHook };
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
|
@@ -1,63 +1,7 @@
|
|
|
1
|
-
import
|
|
1
|
+
import "./config.mjs";
|
|
2
|
+
import "./package-json.mjs";
|
|
3
|
+
import "./prepare.mjs";
|
|
2
4
|
import "./sanitize.mjs";
|
|
3
5
|
import "./cache.mjs";
|
|
4
|
-
import {
|
|
5
|
-
import { rmSync } from "node:fs";
|
|
6
|
-
//#region src/retriv/embedding-cache.ts
|
|
7
|
-
const EMBEDDINGS_DB_PATH = join(CACHE_DIR, "embeddings.db");
|
|
8
|
-
let _db = null;
|
|
9
|
-
async function openDb() {
|
|
10
|
-
if (_db) return _db;
|
|
11
|
-
const { DatabaseSync: DB } = await import("node:sqlite");
|
|
12
|
-
const db = new DB(EMBEDDINGS_DB_PATH);
|
|
13
|
-
db.exec("PRAGMA journal_mode=WAL");
|
|
14
|
-
db.exec("PRAGMA busy_timeout=5000");
|
|
15
|
-
db.exec(`CREATE TABLE IF NOT EXISTS embeddings (text_hash TEXT PRIMARY KEY, embedding BLOB NOT NULL)`);
|
|
16
|
-
db.exec(`CREATE TABLE IF NOT EXISTS meta (key TEXT PRIMARY KEY, value TEXT NOT NULL)`);
|
|
17
|
-
_db = db;
|
|
18
|
-
return db;
|
|
19
|
-
}
|
|
20
|
-
function closeDb() {
|
|
21
|
-
if (_db) {
|
|
22
|
-
_db.close();
|
|
23
|
-
_db = null;
|
|
24
|
-
}
|
|
25
|
-
}
|
|
26
|
-
function createSqliteStorage(db) {
|
|
27
|
-
const getStmt = db.prepare("SELECT embedding FROM embeddings WHERE text_hash = ?");
|
|
28
|
-
const setStmt = db.prepare("INSERT OR IGNORE INTO embeddings (text_hash, embedding) VALUES (?, ?)");
|
|
29
|
-
return {
|
|
30
|
-
get: (hash) => {
|
|
31
|
-
const row = getStmt.get(hash);
|
|
32
|
-
if (!row) return null;
|
|
33
|
-
return new Float32Array(row.embedding.buffer, row.embedding.byteOffset, row.embedding.byteLength / 4);
|
|
34
|
-
},
|
|
35
|
-
set: (hash, embedding) => {
|
|
36
|
-
const arr = embedding instanceof Float32Array ? embedding : new Float32Array(embedding);
|
|
37
|
-
setStmt.run(hash, Buffer.from(arr.buffer, arr.byteOffset, arr.byteLength));
|
|
38
|
-
}
|
|
39
|
-
};
|
|
40
|
-
}
|
|
41
|
-
async function cachedEmbeddings(config) {
|
|
42
|
-
const { cachedEmbeddings: retrivCached } = await import("retriv/embeddings/cached");
|
|
43
|
-
const db = await openDb();
|
|
44
|
-
const storage = createSqliteStorage(db);
|
|
45
|
-
const originalResolve = config.resolve;
|
|
46
|
-
return retrivCached({ async resolve() {
|
|
47
|
-
const resolved = await originalResolve();
|
|
48
|
-
const getMetaStmt = db.prepare("SELECT value FROM meta WHERE key = ?");
|
|
49
|
-
const setMetaStmt = db.prepare("INSERT OR REPLACE INTO meta (key, value) VALUES (?, ?)");
|
|
50
|
-
const storedDims = getMetaStmt.get("dimensions");
|
|
51
|
-
if (storedDims && Number(storedDims.value) !== resolved.dimensions) db.exec("DELETE FROM embeddings");
|
|
52
|
-
setMetaStmt.run("dimensions", String(resolved.dimensions));
|
|
53
|
-
return resolved;
|
|
54
|
-
} }, { storage });
|
|
55
|
-
}
|
|
56
|
-
function clearEmbeddingCache() {
|
|
57
|
-
closeDb();
|
|
58
|
-
rmSync(EMBEDDINGS_DB_PATH, { force: true });
|
|
59
|
-
}
|
|
60
|
-
//#endregion
|
|
6
|
+
import { n as clearEmbeddingCache, t as cachedEmbeddings } from "./embedding-cache2.mjs";
|
|
61
7
|
export { cachedEmbeddings, clearEmbeddingCache };
|
|
62
|
-
|
|
63
|
-
//# sourceMappingURL=embedding-cache.mjs.map
|
|
@@ -0,0 +1,61 @@
|
|
|
1
|
+
import { t as CACHE_DIR } from "./config.mjs";
|
|
2
|
+
import { join } from "pathe";
|
|
3
|
+
import { rmSync } from "node:fs";
|
|
4
|
+
//#region src/retriv/embedding-cache.ts
|
|
5
|
+
const EMBEDDINGS_DB_PATH = join(CACHE_DIR, "embeddings.db");
|
|
6
|
+
let _db = null;
|
|
7
|
+
async function openDb() {
|
|
8
|
+
if (_db) return _db;
|
|
9
|
+
const { DatabaseSync: DB } = await import("node:sqlite");
|
|
10
|
+
const db = new DB(EMBEDDINGS_DB_PATH);
|
|
11
|
+
db.exec("PRAGMA journal_mode=WAL");
|
|
12
|
+
db.exec("PRAGMA busy_timeout=5000");
|
|
13
|
+
db.exec(`CREATE TABLE IF NOT EXISTS embeddings (text_hash TEXT PRIMARY KEY, embedding BLOB NOT NULL)`);
|
|
14
|
+
db.exec(`CREATE TABLE IF NOT EXISTS meta (key TEXT PRIMARY KEY, value TEXT NOT NULL)`);
|
|
15
|
+
_db = db;
|
|
16
|
+
return db;
|
|
17
|
+
}
|
|
18
|
+
function closeDb() {
|
|
19
|
+
if (_db) {
|
|
20
|
+
_db.close();
|
|
21
|
+
_db = null;
|
|
22
|
+
}
|
|
23
|
+
}
|
|
24
|
+
function createSqliteStorage(db) {
|
|
25
|
+
const getStmt = db.prepare("SELECT embedding FROM embeddings WHERE text_hash = ?");
|
|
26
|
+
const setStmt = db.prepare("INSERT OR IGNORE INTO embeddings (text_hash, embedding) VALUES (?, ?)");
|
|
27
|
+
return {
|
|
28
|
+
get: (hash) => {
|
|
29
|
+
const row = getStmt.get(hash);
|
|
30
|
+
if (!row) return null;
|
|
31
|
+
return new Float32Array(row.embedding.buffer, row.embedding.byteOffset, row.embedding.byteLength / 4);
|
|
32
|
+
},
|
|
33
|
+
set: (hash, embedding) => {
|
|
34
|
+
const arr = embedding instanceof Float32Array ? embedding : new Float32Array(embedding);
|
|
35
|
+
setStmt.run(hash, Buffer.from(arr.buffer, arr.byteOffset, arr.byteLength));
|
|
36
|
+
}
|
|
37
|
+
};
|
|
38
|
+
}
|
|
39
|
+
async function cachedEmbeddings(config) {
|
|
40
|
+
const { cachedEmbeddings: retrivCached } = await import("retriv/embeddings/cached");
|
|
41
|
+
const db = await openDb();
|
|
42
|
+
const storage = createSqliteStorage(db);
|
|
43
|
+
const originalResolve = config.resolve;
|
|
44
|
+
return retrivCached({ async resolve() {
|
|
45
|
+
const resolved = await originalResolve();
|
|
46
|
+
const getMetaStmt = db.prepare("SELECT value FROM meta WHERE key = ?");
|
|
47
|
+
const setMetaStmt = db.prepare("INSERT OR REPLACE INTO meta (key, value) VALUES (?, ?)");
|
|
48
|
+
const storedDims = getMetaStmt.get("dimensions");
|
|
49
|
+
if (storedDims && Number(storedDims.value) !== resolved.dimensions) db.exec("DELETE FROM embeddings");
|
|
50
|
+
setMetaStmt.run("dimensions", String(resolved.dimensions));
|
|
51
|
+
return resolved;
|
|
52
|
+
} }, { storage });
|
|
53
|
+
}
|
|
54
|
+
function clearEmbeddingCache() {
|
|
55
|
+
closeDb();
|
|
56
|
+
rmSync(EMBEDDINGS_DB_PATH, { force: true });
|
|
57
|
+
}
|
|
58
|
+
//#endregion
|
|
59
|
+
export { clearEmbeddingCache as n, cachedEmbeddings as t };
|
|
60
|
+
|
|
61
|
+
//# sourceMappingURL=embedding-cache2.mjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"embedding-cache2.mjs","names":[],"sources":["../../src/retriv/embedding-cache.ts"],"sourcesContent":["import type { DatabaseSync } from 'node:sqlite'\nimport type { Embedding } from 'retriv'\nimport { rmSync } from 'node:fs'\nimport { join } from 'pathe'\nimport { CACHE_DIR } from '../cache/index.ts'\n\ninterface EmbeddingConfig {\n resolve: () => Promise<{ embedder: (texts: string[]) => Promise<Embedding[]>, dimensions: number, maxTokens?: number }>\n}\n\nconst EMBEDDINGS_DB_PATH = join(CACHE_DIR, 'embeddings.db')\n\nlet _db: DatabaseSync | null = null\n\nasync function openDb(): Promise<DatabaseSync> {\n if (_db)\n return _db\n const { DatabaseSync: DB } = await import('node:sqlite')\n const db = new DB(EMBEDDINGS_DB_PATH)\n db.exec('PRAGMA journal_mode=WAL')\n db.exec('PRAGMA busy_timeout=5000')\n db.exec(`CREATE TABLE IF NOT EXISTS embeddings (text_hash TEXT PRIMARY KEY, embedding BLOB NOT NULL)`)\n db.exec(`CREATE TABLE IF NOT EXISTS meta (key TEXT PRIMARY KEY, value TEXT NOT NULL)`)\n _db = db\n return db\n}\n\nfunction closeDb(): void {\n if (_db) {\n _db.close()\n _db = null\n }\n}\n\nfunction createSqliteStorage(db: DatabaseSync) {\n const getStmt = db.prepare('SELECT embedding FROM embeddings WHERE text_hash = ?')\n const setStmt = db.prepare('INSERT OR IGNORE INTO embeddings (text_hash, embedding) VALUES (?, ?)')\n\n return {\n get: (hash: string): Embedding | null => {\n const row = getStmt.get(hash) as { embedding: Buffer } | undefined\n if (!row)\n return null\n return new Float32Array(row.embedding.buffer, row.embedding.byteOffset, row.embedding.byteLength / 4)\n },\n set: (hash: string, embedding: Embedding): void => {\n const arr = embedding instanceof Float32Array ? embedding : new Float32Array(embedding)\n setStmt.run(hash, Buffer.from(arr.buffer, arr.byteOffset, arr.byteLength))\n },\n }\n}\n\nexport async function cachedEmbeddings(config: EmbeddingConfig): Promise<EmbeddingConfig> {\n const { cachedEmbeddings: retrivCached } = await import('retriv/embeddings/cached')\n const db = await openDb()\n const storage = createSqliteStorage(db)\n\n const originalResolve = config.resolve\n const validatedConfig: EmbeddingConfig = {\n async resolve() {\n const resolved = await originalResolve()\n const getMetaStmt = db.prepare('SELECT value FROM meta WHERE key = ?')\n const setMetaStmt = db.prepare('INSERT OR REPLACE INTO meta (key, value) VALUES (?, ?)')\n\n const storedDims = getMetaStmt.get('dimensions') as { value: string } | undefined\n if (storedDims && Number(storedDims.value) !== resolved.dimensions) {\n db.exec('DELETE FROM embeddings')\n }\n setMetaStmt.run('dimensions', String(resolved.dimensions))\n\n return resolved\n },\n }\n\n return retrivCached(validatedConfig, { storage })\n}\n\nexport function clearEmbeddingCache(): void {\n closeDb()\n rmSync(EMBEDDINGS_DB_PATH, { force: true })\n}\n"],"mappings":";;;;AAUA,MAAM,qBAAqB,KAAK,WAAW,gBAAgB;AAE3D,IAAI,MAA2B;AAE/B,eAAe,SAAgC;AAC7C,KAAI,IACF,QAAO;CACT,MAAM,EAAE,cAAc,OAAO,MAAM,OAAO;CAC1C,MAAM,KAAK,IAAI,GAAG,mBAAmB;AACrC,IAAG,KAAK,0BAA0B;AAClC,IAAG,KAAK,2BAA2B;AACnC,IAAG,KAAK,8FAA8F;AACtG,IAAG,KAAK,8EAA8E;AACtF,OAAM;AACN,QAAO;;AAGT,SAAS,UAAgB;AACvB,KAAI,KAAK;AACP,MAAI,OAAO;AACX,QAAM;;;AAIV,SAAS,oBAAoB,IAAkB;CAC7C,MAAM,UAAU,GAAG,QAAQ,uDAAuD;CAClF,MAAM,UAAU,GAAG,QAAQ,wEAAwE;AAEnG,QAAO;EACL,MAAM,SAAmC;GACvC,MAAM,MAAM,QAAQ,IAAI,KAAK;AAC7B,OAAI,CAAC,IACH,QAAO;AACT,UAAO,IAAI,aAAa,IAAI,UAAU,QAAQ,IAAI,UAAU,YAAY,IAAI,UAAU,aAAa,EAAE;;EAEvG,MAAM,MAAc,cAA+B;GACjD,MAAM,MAAM,qBAAqB,eAAe,YAAY,IAAI,aAAa,UAAU;AACvF,WAAQ,IAAI,MAAM,OAAO,KAAK,IAAI,QAAQ,IAAI,YAAY,IAAI,WAAW,CAAC;;EAE7E;;AAGH,eAAsB,iBAAiB,QAAmD;CACxF,MAAM,EAAE,kBAAkB,iBAAiB,MAAM,OAAO;CACxD,MAAM,KAAK,MAAM,QAAQ;CACzB,MAAM,UAAU,oBAAoB,GAAG;CAEvC,MAAM,kBAAkB,OAAO;AAiB/B,QAAO,aAhBkC,EACvC,MAAM,UAAU;EACd,MAAM,WAAW,MAAM,iBAAiB;EACxC,MAAM,cAAc,GAAG,QAAQ,uCAAuC;EACtE,MAAM,cAAc,GAAG,QAAQ,yDAAyD;EAExF,MAAM,aAAa,YAAY,IAAI,aAAa;AAChD,MAAI,cAAc,OAAO,WAAW,MAAM,KAAK,SAAS,WACtD,IAAG,KAAK,yBAAyB;AAEnC,cAAY,IAAI,cAAc,OAAO,SAAS,WAAW,CAAC;AAE1D,SAAO;IAEV,EAEoC,EAAE,SAAS,CAAC;;AAGnD,SAAgB,sBAA4B;AAC1C,UAAS;AACT,QAAO,oBAAoB,EAAE,OAAO,MAAM,CAAC"}
|
package/dist/_chunks/index.d.mts
CHANGED
|
@@ -33,6 +33,18 @@ interface CachedDoc {
|
|
|
33
33
|
content: string;
|
|
34
34
|
}
|
|
35
35
|
//#endregion
|
|
36
|
+
//#region src/core/prepare.d.ts
|
|
37
|
+
/** Resolve package directory: node_modules first, then global cache */
|
|
38
|
+
declare function resolvePkgDir(name: string, cwd: string, version?: string): string | null;
|
|
39
|
+
interface ShippedSkill {
|
|
40
|
+
skillName: string;
|
|
41
|
+
skillDir: string;
|
|
42
|
+
}
|
|
43
|
+
/** Check if package ships a skills/ directory with SKILL.md or _SKILL.md subdirs */
|
|
44
|
+
declare function getShippedSkills(name: string, cwd: string, version?: string): ShippedSkill[];
|
|
45
|
+
/** Create symlink from skills dir to shipped skill dir */
|
|
46
|
+
declare function linkShippedSkill(baseDir: string, skillName: string, targetDir: string): void;
|
|
47
|
+
//#endregion
|
|
36
48
|
//#region src/cache/storage.d.ts
|
|
37
49
|
/**
|
|
38
50
|
* Check if package is cached at given version
|
|
@@ -65,11 +77,6 @@ declare function linkRepoCachedDir(skillDir: string, owner: string, repo: string
|
|
|
65
77
|
* The .skilld/ dirs are gitignored. After clone, `skilld install` recreates from lockfile.
|
|
66
78
|
*/
|
|
67
79
|
declare function linkCachedDir(skillDir: string, name: string, version: string, subdir: string): void;
|
|
68
|
-
/**
|
|
69
|
-
* Resolve the package directory: node_modules first, then cached dist fallback.
|
|
70
|
-
* Returns the path if found, null otherwise.
|
|
71
|
-
*/
|
|
72
|
-
declare function resolvePkgDir(name: string, cwd: string, version?: string): string | null;
|
|
73
80
|
/**
|
|
74
81
|
* Create symlink from .skilld dir to package directory
|
|
75
82
|
*
|
|
@@ -92,17 +99,6 @@ declare function linkPkgNamed(skillDir: string, name: string, cwd: string, versi
|
|
|
92
99
|
* Returns entry points + docs files
|
|
93
100
|
*/
|
|
94
101
|
declare function getPkgKeyFiles(name: string, cwd: string, version?: string): string[];
|
|
95
|
-
/**
|
|
96
|
-
* Check if package ships its own docs folder
|
|
97
|
-
*/
|
|
98
|
-
interface ShippedSkill {
|
|
99
|
-
skillName: string;
|
|
100
|
-
skillDir: string;
|
|
101
|
-
}
|
|
102
|
-
/**
|
|
103
|
-
* Check if package ships a skills/ directory with SKILL.md or _SKILL.md subdirs
|
|
104
|
-
*/
|
|
105
|
-
declare function getShippedSkills(name: string, cwd: string, version?: string): ShippedSkill[];
|
|
106
102
|
/**
|
|
107
103
|
* Write LLM-generated section outputs to global cache for cross-project reuse
|
|
108
104
|
*
|
|
@@ -117,10 +113,6 @@ declare function writeSections(name: string, version: string, sections: Array<{
|
|
|
117
113
|
* Read a cached section from the global references dir
|
|
118
114
|
*/
|
|
119
115
|
declare function readCachedSection(name: string, version: string, file: string): string | null;
|
|
120
|
-
/**
|
|
121
|
-
* Create symlink from skills dir to shipped skill dir
|
|
122
|
-
*/
|
|
123
|
-
declare function linkShippedSkill(baseDir: string, skillName: string, targetDir: string): void;
|
|
124
116
|
declare function hasShippedDocs(name: string, cwd: string, version?: string): boolean;
|
|
125
117
|
/**
|
|
126
118
|
* List all cached packages
|
|
@@ -162,5 +154,5 @@ declare function getCacheKey(name: string, version: string): string;
|
|
|
162
154
|
*/
|
|
163
155
|
declare function getCacheDir(name: string, version: string): string;
|
|
164
156
|
//#endregion
|
|
165
|
-
export { REPOS_DIR as A,
|
|
157
|
+
export { REPOS_DIR as A, linkShippedSkill as C, CachedPackage as D, CachedDoc as E, getRepoCacheDir as M, CACHE_DIR as O, getShippedSkills as S, CacheConfig as T, readCachedSection as _, clearCache as a, writeToRepoCache as b, hasShippedDocs as c, linkPkg as d, linkPkgNamed as f, readCachedDocs as g, listReferenceFiles as h, clearAllCache as i, getPackageDbPath as j, REFERENCES_DIR as k, isCached as l, listCached as m, getCacheKey as n, ensureCacheDir as o, linkRepoCachedDir as p, getVersionKey as r, getPkgKeyFiles as s, getCacheDir as t, linkCachedDir as u, writeSections as v, resolvePkgDir as w, ShippedSkill as x, writeToCache as y };
|
|
166
158
|
//# sourceMappingURL=index.d.mts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.mts","names":[],"sources":["../../src/cache/config.ts","../../src/cache/types.ts","../../src/cache/storage.ts","../../src/cache/version.ts"],"mappings":";;AASA;;;cAAa,SAAA;;cAGA,cAAA;;cAGA,SAAA;;iBAGG,eAAA,CAAgB,KAAA,UAAe,IAAA;AAH/C;AAAA,iBAUgB,gBAAA,CAAiB,IAAA,UAAc,OAAA;;;;AAhB/C;;UCLiB,WAAA;EDKkC;ECHjD,IAAA;EDMW;ECJX,OAAA;AAAA;AAAA,UAGe,aAAA;EACf,IAAA;EACA,OAAA;EACA,GAAA;AAAA;AAAA,UAGe,SAAA;EACf,IAAA;EACA,OAAA;AAAA;;;;;
|
|
1
|
+
{"version":3,"file":"index.d.mts","names":[],"sources":["../../src/cache/config.ts","../../src/cache/types.ts","../../src/core/prepare.ts","../../src/cache/storage.ts","../../src/cache/version.ts"],"mappings":";;AASA;;;cAAa,SAAA;;cAGA,cAAA;;cAGA,SAAA;;iBAGG,eAAA,CAAgB,KAAA,UAAe,IAAA;AAH/C;AAAA,iBAUgB,gBAAA,CAAiB,IAAA,UAAc,OAAA;;;;AAhB/C;;UCLiB,WAAA;EDKkC;ECHjD,IAAA;EDMW;ECJX,OAAA;AAAA;AAAA,UAGe,aAAA;EACf,IAAA;EACA,OAAA;EACA,GAAA;AAAA;AAAA,UAGe,SAAA;EACf,IAAA;EACA,OAAA;AAAA;;;;iBCLc,aAAA,CAAc,IAAA,UAAc,GAAA,UAAa,OAAA;AAAA,UAkCxC,YAAA;EACf,SAAA;EACA,QAAA;AAAA;AFhCF;AAAA,iBEoCgB,gBAAA,CAAiB,IAAA,UAAc,GAAA,UAAa,OAAA,YAAmB,YAAA;;iBAe/D,gBAAA,CAAiB,OAAA,UAAiB,SAAA,UAAmB,SAAA;;;;;AFzDrE;iBGmBgB,QAAA,CAAS,IAAA,UAAc,OAAA;;;;iBAOvB,cAAA,CAAA;;;;iBAQA,YAAA,CACd,IAAA,UACA,OAAA,UACA,IAAA,EAAM,SAAA;AH/BR;;;AAAA,iBGgDgB,gBAAA,CACd,KAAA,UACA,IAAA,UACA,IAAA,EAAM,SAAA;;AH5CR;;;iBG8DgB,iBAAA,CAAkB,QAAA,UAAkB,KAAA,UAAe,IAAA,UAAc,MAAA;;;;;AFnFjF;;;;;iBEyGgB,aAAA,CAAc,QAAA,UAAkB,IAAA,UAAc,OAAA,UAAiB,MAAA;;AF5F/E;;;;;;;iBEyHgB,OAAA,CAAQ,QAAA,UAAkB,IAAA,UAAc,GAAA,UAAa,OAAA;AD5HrE;;;;;;;AAAA,iBCoJgB,YAAA,CAAa,QAAA,UAAkB,IAAA,UAAc,GAAA,UAAa,OAAA;;ADlH1E;;;iBCwIgB,cAAA,CAAe,IAAA,UAAc,GAAA,UAAa,OAAA;;ADlI1D;;;;;iBCyKgB,aAAA,CAAc,IAAA,UAAc,OAAA,UAAiB,QAAA,EAAU,KAAA;EAAQ,IAAA;EAAc,OAAA;AAAA;;AD1J7F;;iBCsKgB,iBAAA,CAAkB,IAAA,UAAc,OAAA,UAAiB,IAAA;AAAA,iBAOjD,cAAA,CAAe,IAAA,UAAc,GAAA,UAAa,OAAA;;;;iBAiB1C,UAAA,CAAA,GAAc,aAAA;;;;iBAed,cAAA,CAAe,IAAA,UAAc,OAAA,WAAkB,SAAA;AAnP/D;;;AAAA,iBAkRgB,UAAA,CAAW,IAAA,UAAc,OAAA;;AA3QzC;;iBAuRgB,aAAA,CAAA;;;AA/QhB;;iBA8RgB,kBAAA,CAAmB,QAAA,UAAkB,QAAA;;;;AHnUrD;;;;;iBIOgB,aAAA,CAAc,OAAA;;;;iBAOd,WAAA,CAAY,IAAA,UAAc,OAAA;AJR1C;;;;AAAA,iBIgBgB,WAAA,CAAY,IAAA,UAAc,OAAA"}
|