skyl.dev 0.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/bundle.json +1 -0
- package/dist/bin.d.ts +3 -0
- package/dist/bin.d.ts.map +1 -0
- package/dist/bin.js +4 -0
- package/dist/bin.js.map +1 -0
- package/dist/cli.d.ts +2 -0
- package/dist/cli.d.ts.map +1 -0
- package/dist/cli.js +158 -0
- package/dist/cli.js.map +1 -0
- package/dist/commands/add.d.ts +10 -0
- package/dist/commands/add.d.ts.map +1 -0
- package/dist/commands/add.js +38 -0
- package/dist/commands/add.js.map +1 -0
- package/dist/commands/audit.d.ts +16 -0
- package/dist/commands/audit.d.ts.map +1 -0
- package/dist/commands/audit.js +91 -0
- package/dist/commands/audit.js.map +1 -0
- package/dist/commands/context.d.ts +17 -0
- package/dist/commands/context.d.ts.map +1 -0
- package/dist/commands/context.js +47 -0
- package/dist/commands/context.js.map +1 -0
- package/dist/commands/diff.d.ts +12 -0
- package/dist/commands/diff.d.ts.map +1 -0
- package/dist/commands/diff.js +79 -0
- package/dist/commands/diff.js.map +1 -0
- package/dist/commands/learn.d.ts +18 -0
- package/dist/commands/learn.d.ts.map +1 -0
- package/dist/commands/learn.js +115 -0
- package/dist/commands/learn.js.map +1 -0
- package/dist/commands/lint.d.ts +14 -0
- package/dist/commands/lint.d.ts.map +1 -0
- package/dist/commands/lint.js +109 -0
- package/dist/commands/lint.js.map +1 -0
- package/dist/commands/list.d.ts +6 -0
- package/dist/commands/list.d.ts.map +1 -0
- package/dist/commands/list.js +60 -0
- package/dist/commands/list.js.map +1 -0
- package/dist/commands/remove.d.ts +16 -0
- package/dist/commands/remove.d.ts.map +1 -0
- package/dist/commands/remove.js +73 -0
- package/dist/commands/remove.js.map +1 -0
- package/dist/commands/scan.d.ts +10 -0
- package/dist/commands/scan.d.ts.map +1 -0
- package/dist/commands/scan.js +60 -0
- package/dist/commands/scan.js.map +1 -0
- package/dist/commands/update.d.ts +11 -0
- package/dist/commands/update.d.ts.map +1 -0
- package/dist/commands/update.js +135 -0
- package/dist/commands/update.js.map +1 -0
- package/dist/context.d.ts +44 -0
- package/dist/context.d.ts.map +1 -0
- package/dist/context.js +179 -0
- package/dist/context.js.map +1 -0
- package/dist/ignore.d.ts +21 -0
- package/dist/ignore.d.ts.map +1 -0
- package/dist/ignore.js +79 -0
- package/dist/ignore.js.map +1 -0
- package/dist/install.d.ts +10 -0
- package/dist/install.d.ts.map +1 -0
- package/dist/install.js +54 -0
- package/dist/install.js.map +1 -0
- package/dist/learn.d.ts +45 -0
- package/dist/learn.d.ts.map +1 -0
- package/dist/learn.js +146 -0
- package/dist/learn.js.map +1 -0
- package/dist/registry.d.ts +23 -0
- package/dist/registry.d.ts.map +1 -0
- package/dist/registry.js +38 -0
- package/dist/registry.js.map +1 -0
- package/dist/scan.d.ts +3 -0
- package/dist/scan.d.ts.map +1 -0
- package/dist/scan.js +104 -0
- package/dist/scan.js.map +1 -0
- package/dist/state.d.ts +31 -0
- package/dist/state.d.ts.map +1 -0
- package/dist/state.js +39 -0
- package/dist/state.js.map +1 -0
- package/dist/ui.d.ts +17 -0
- package/dist/ui.d.ts.map +1 -0
- package/dist/ui.js +35 -0
- package/dist/ui.js.map +1 -0
- package/node_modules/@skyl/core/dist/audit.d.ts +48 -0
- package/node_modules/@skyl/core/dist/audit.d.ts.map +1 -0
- package/node_modules/@skyl/core/dist/audit.js +99 -0
- package/node_modules/@skyl/core/dist/audit.js.map +1 -0
- package/node_modules/@skyl/core/dist/detect.d.ts +15 -0
- package/node_modules/@skyl/core/dist/detect.d.ts.map +1 -0
- package/node_modules/@skyl/core/dist/detect.js +62 -0
- package/node_modules/@skyl/core/dist/detect.js.map +1 -0
- package/node_modules/@skyl/core/dist/diff.d.ts +32 -0
- package/node_modules/@skyl/core/dist/diff.d.ts.map +1 -0
- package/node_modules/@skyl/core/dist/diff.js +119 -0
- package/node_modules/@skyl/core/dist/diff.js.map +1 -0
- package/node_modules/@skyl/core/dist/errors.d.ts +21 -0
- package/node_modules/@skyl/core/dist/errors.d.ts.map +1 -0
- package/node_modules/@skyl/core/dist/errors.js +25 -0
- package/node_modules/@skyl/core/dist/errors.js.map +1 -0
- package/node_modules/@skyl/core/dist/index.d.ts +14 -0
- package/node_modules/@skyl/core/dist/index.d.ts.map +1 -0
- package/node_modules/@skyl/core/dist/index.js +14 -0
- package/node_modules/@skyl/core/dist/index.js.map +1 -0
- package/node_modules/@skyl/core/dist/lint.d.ts +28 -0
- package/node_modules/@skyl/core/dist/lint.d.ts.map +1 -0
- package/node_modules/@skyl/core/dist/lint.js +169 -0
- package/node_modules/@skyl/core/dist/lint.js.map +1 -0
- package/node_modules/@skyl/core/dist/lockfile.d.ts +37 -0
- package/node_modules/@skyl/core/dist/lockfile.d.ts.map +1 -0
- package/node_modules/@skyl/core/dist/lockfile.js +47 -0
- package/node_modules/@skyl/core/dist/lockfile.js.map +1 -0
- package/node_modules/@skyl/core/dist/match.d.ts +19 -0
- package/node_modules/@skyl/core/dist/match.d.ts.map +1 -0
- package/node_modules/@skyl/core/dist/match.js +72 -0
- package/node_modules/@skyl/core/dist/match.js.map +1 -0
- package/node_modules/@skyl/core/dist/names.d.ts +11 -0
- package/node_modules/@skyl/core/dist/names.d.ts.map +1 -0
- package/node_modules/@skyl/core/dist/names.js +31 -0
- package/node_modules/@skyl/core/dist/names.js.map +1 -0
- package/node_modules/@skyl/core/dist/parse.d.ts +22 -0
- package/node_modules/@skyl/core/dist/parse.d.ts.map +1 -0
- package/node_modules/@skyl/core/dist/parse.js +163 -0
- package/node_modules/@skyl/core/dist/parse.js.map +1 -0
- package/node_modules/@skyl/core/dist/resolve.d.ts +12 -0
- package/node_modules/@skyl/core/dist/resolve.d.ts.map +1 -0
- package/node_modules/@skyl/core/dist/resolve.js +40 -0
- package/node_modules/@skyl/core/dist/resolve.js.map +1 -0
- package/node_modules/@skyl/core/dist/source.d.ts +35 -0
- package/node_modules/@skyl/core/dist/source.d.ts.map +1 -0
- package/node_modules/@skyl/core/dist/source.js +85 -0
- package/node_modules/@skyl/core/dist/source.js.map +1 -0
- package/node_modules/@skyl/core/dist/targets.d.ts +20 -0
- package/node_modules/@skyl/core/dist/targets.d.ts.map +1 -0
- package/node_modules/@skyl/core/dist/targets.js +24 -0
- package/node_modules/@skyl/core/dist/targets.js.map +1 -0
- package/node_modules/@skyl/core/dist/types.d.ts +51 -0
- package/node_modules/@skyl/core/dist/types.d.ts.map +1 -0
- package/node_modules/@skyl/core/dist/types.js +2 -0
- package/node_modules/@skyl/core/dist/types.js.map +1 -0
- package/node_modules/@skyl/core/package.json +20 -0
- package/package.json +43 -0
|
@@ -0,0 +1,115 @@
|
|
|
1
|
+
import { spawn } from 'node:child_process';
|
|
2
|
+
import { mkdir, readFile, writeFile } from 'node:fs/promises';
|
|
3
|
+
import { dirname, join } from 'node:path';
|
|
4
|
+
import { buildContext } from "../context.js";
|
|
5
|
+
import { readLockfile, resolveTarget } from "../install.js";
|
|
6
|
+
import { extractMarkdown, learnPrompt, preserved, reattach, withCaution, LEARNED_NAME } from "../learn.js";
|
|
7
|
+
import { bold, confirm, cyan, dim, err, green, out, red, tokens, yellow } from "../ui.js";
|
|
8
|
+
/** The one shorthand whose headless flag is known to work. Anything else is given in full. */
|
|
9
|
+
const SHORTHAND = { claude: ['claude', '-p'] };
|
|
10
|
+
/**
|
|
11
|
+
* Derive a project knowledge skill from this repository.
|
|
12
|
+
*
|
|
13
|
+
* The agent calls skyl, not the reverse. Selecting the files, keeping the hand-written
|
|
14
|
+
* text, and merging the result are deterministic and live here; the reading is done by
|
|
15
|
+
* whichever model the user already pays for. That is why there is no API key anywhere in
|
|
16
|
+
* this command, and why `--print-prompt` is a first class path rather than a fallback.
|
|
17
|
+
*/
|
|
18
|
+
export async function learn(opts) {
|
|
19
|
+
const lock = await readLockfile(opts.root);
|
|
20
|
+
const target = resolveTarget(opts.target, lock);
|
|
21
|
+
const file = join(opts.root, target.dir, target.fileFor(LEARNED_NAME));
|
|
22
|
+
const existing = await readFile(file, 'utf8').catch(() => undefined);
|
|
23
|
+
const keep = preserved(existing);
|
|
24
|
+
const bundle = await buildContext(opts.root, { installed: Object.keys(lock?.skills ?? {}) });
|
|
25
|
+
if (bundle.files.length === 0) {
|
|
26
|
+
err(`${yellow('Nothing to read here.')} No documentation, schema or source files were selected.`);
|
|
27
|
+
return 1;
|
|
28
|
+
}
|
|
29
|
+
const prompt = learnPrompt(bundle, keep);
|
|
30
|
+
if (opts.printPrompt === true || !opts.agent) {
|
|
31
|
+
if (opts.outFile) {
|
|
32
|
+
await writeFile(opts.outFile, prompt, 'utf8');
|
|
33
|
+
out(` ${green('Written.')} ${opts.outFile}`);
|
|
34
|
+
}
|
|
35
|
+
else {
|
|
36
|
+
process.stdout.write(prompt);
|
|
37
|
+
}
|
|
38
|
+
if (!opts.agent && opts.printPrompt !== true) {
|
|
39
|
+
err('');
|
|
40
|
+
err(` ${dim('Paste this into any agent, or run')} ${cyan('skyl learn --agent claude')} ${dim('to do it here.')}`);
|
|
41
|
+
}
|
|
42
|
+
return 0;
|
|
43
|
+
}
|
|
44
|
+
const command = SHORTHAND[opts.agent] ?? opts.agent.split(' ');
|
|
45
|
+
out();
|
|
46
|
+
out(` ${bold('Reading this project')} ${dim(`${bundle.files.length} files, ${tokens(prompt.split(/\s+/).length)}`)}`);
|
|
47
|
+
for (const w of bundle.withheld)
|
|
48
|
+
out(` ${yellow('withheld')} ${w.path} ${dim(w.why)}`);
|
|
49
|
+
out(` ${dim(`through ${command.join(' ')}, which uses your own account`)}`);
|
|
50
|
+
out();
|
|
51
|
+
if (!(await confirm(` Send ${bundle.files.length} files to ${command[0]}?`, opts.yes === true))) {
|
|
52
|
+
out(` ${dim('Nothing sent.')}`);
|
|
53
|
+
return 1;
|
|
54
|
+
}
|
|
55
|
+
const output = await pipeTo(command, prompt).catch((cause) => {
|
|
56
|
+
err(` ${red('Could not run')} ${command.join(' ')}`);
|
|
57
|
+
err(` ${dim(cause.message)}`);
|
|
58
|
+
return undefined;
|
|
59
|
+
});
|
|
60
|
+
if (output === undefined)
|
|
61
|
+
return 1;
|
|
62
|
+
const generated = extractMarkdown(output);
|
|
63
|
+
if (!generated) {
|
|
64
|
+
err(` ${red('No skill in the output.')} ${dim('Re-run with --print-prompt and paste it somewhere you can see the answer.')}`);
|
|
65
|
+
return 1;
|
|
66
|
+
}
|
|
67
|
+
const date = new Date().toISOString().slice(0, 10);
|
|
68
|
+
const sha = await gitSha(opts.root);
|
|
69
|
+
const text = withCaution(reattach(generated, keep), date, sha);
|
|
70
|
+
if (existing !== undefined) {
|
|
71
|
+
const history = join(opts.root, '.skyl', 'history', `project-core.${sha ?? date}.md`);
|
|
72
|
+
await mkdir(dirname(history), { recursive: true });
|
|
73
|
+
await writeFile(history, existing, 'utf8');
|
|
74
|
+
}
|
|
75
|
+
await mkdir(dirname(file), { recursive: true });
|
|
76
|
+
await writeFile(file, text, 'utf8');
|
|
77
|
+
const open = (text.match(/<!-- unanswered -->/g) ?? []).length;
|
|
78
|
+
out();
|
|
79
|
+
out(` ${green(existing ? 'Refreshed.' : 'Written.')} ${dim(file.replace(opts.root + '/', ''))}`);
|
|
80
|
+
if (keep.manual) {
|
|
81
|
+
const lines = keep.manual.split('\n').length;
|
|
82
|
+
out(` ${dim(`## Manual carried over, ${lines} line${lines === 1 ? '' : 's'}`)}`);
|
|
83
|
+
}
|
|
84
|
+
if (open > 0)
|
|
85
|
+
out(` ${yellow(`${open} question${open === 1 ? '' : 's'}`)} ${dim('left for you, marked <!-- unanswered -->')}`);
|
|
86
|
+
out();
|
|
87
|
+
return 0;
|
|
88
|
+
}
|
|
89
|
+
function pipeTo(command, input) {
|
|
90
|
+
return new Promise((resolve, reject) => {
|
|
91
|
+
const child = spawn(command[0], command.slice(1), { stdio: ['pipe', 'pipe', 'inherit'] });
|
|
92
|
+
let stdout = '';
|
|
93
|
+
child.stdout.setEncoding('utf8');
|
|
94
|
+
child.stdout.on('data', (d) => { stdout += d; });
|
|
95
|
+
child.on('error', reject);
|
|
96
|
+
child.on('close', (code) => {
|
|
97
|
+
if (code === 0)
|
|
98
|
+
resolve(stdout);
|
|
99
|
+
else
|
|
100
|
+
reject(new Error(`exited with code ${String(code)}`));
|
|
101
|
+
});
|
|
102
|
+
child.stdin.end(input, 'utf8');
|
|
103
|
+
});
|
|
104
|
+
}
|
|
105
|
+
async function gitSha(root) {
|
|
106
|
+
return new Promise((resolve) => {
|
|
107
|
+
const child = spawn('git', ['-C', root, 'rev-parse', '--short', 'HEAD'], { stdio: ['ignore', 'pipe', 'ignore'] });
|
|
108
|
+
let out = '';
|
|
109
|
+
child.stdout.setEncoding('utf8');
|
|
110
|
+
child.stdout.on('data', (d) => { out += d; });
|
|
111
|
+
child.on('error', () => resolve(undefined));
|
|
112
|
+
child.on('close', (code) => resolve(code === 0 && out.trim() !== '' ? out.trim() : undefined));
|
|
113
|
+
});
|
|
114
|
+
}
|
|
115
|
+
//# sourceMappingURL=learn.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"learn.js","sourceRoot":"","sources":["../../src/commands/learn.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
export interface LintOptions {
|
|
2
|
+
root: string;
|
|
3
|
+
paths: string[];
|
|
4
|
+
strict?: boolean | undefined;
|
|
5
|
+
}
|
|
6
|
+
/**
|
|
7
|
+
* Check skills against the spec.
|
|
8
|
+
*
|
|
9
|
+
* The registry repository has its own validator in Python. Keeping both is deliberate:
|
|
10
|
+
* they are independent readings of the same document, CI runs both, and a disagreement
|
|
11
|
+
* between them surfaces as a failure rather than as silence.
|
|
12
|
+
*/
|
|
13
|
+
export declare function lint(opts: LintOptions): Promise<number>;
|
|
14
|
+
//# sourceMappingURL=lint.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"lint.d.ts","sourceRoot":"","sources":["../../src/commands/lint.ts"],"names":[],"mappings":"AAKA,MAAM,WAAW,WAAW;IAC1B,IAAI,EAAE,MAAM,CAAC;IACb,KAAK,EAAE,MAAM,EAAE,CAAC;IAChB,MAAM,CAAC,EAAE,OAAO,GAAG,SAAS,CAAC;CAC9B;AAqBD;;;;;;GAMG;AACH,wBAAsB,IAAI,CAAC,IAAI,EAAE,WAAW,GAAG,OAAO,CAAC,MAAM,CAAC,CA+D7D"}
|
|
@@ -0,0 +1,109 @@
|
|
|
1
|
+
import { readdir, readFile, stat as statFile } from 'node:fs/promises';
|
|
2
|
+
import { join, relative } from 'node:path';
|
|
3
|
+
import { lintRegistry, lintSkill, parseSkill } from '@skyl/core';
|
|
4
|
+
import { bold, cyan, dim, err, green, out, red, yellow } from "../ui.js";
|
|
5
|
+
async function skillFiles(path) {
|
|
6
|
+
const info = await statFile(path).catch(() => undefined);
|
|
7
|
+
if (!info)
|
|
8
|
+
return [];
|
|
9
|
+
if (info.isFile())
|
|
10
|
+
return [path];
|
|
11
|
+
const out = [];
|
|
12
|
+
const walk = async (dir, depth) => {
|
|
13
|
+
if (depth > 3)
|
|
14
|
+
return;
|
|
15
|
+
for (const entry of await readdir(dir, { withFileTypes: true })) {
|
|
16
|
+
if (entry.name.startsWith('.'))
|
|
17
|
+
continue;
|
|
18
|
+
const full = join(dir, entry.name);
|
|
19
|
+
if (entry.isDirectory())
|
|
20
|
+
await walk(full, depth + 1);
|
|
21
|
+
else if (entry.name === 'SKILL.md')
|
|
22
|
+
out.push(full);
|
|
23
|
+
}
|
|
24
|
+
};
|
|
25
|
+
await walk(path, 0);
|
|
26
|
+
return out.sort();
|
|
27
|
+
}
|
|
28
|
+
/**
|
|
29
|
+
* Check skills against the spec.
|
|
30
|
+
*
|
|
31
|
+
* The registry repository has its own validator in Python. Keeping both is deliberate:
|
|
32
|
+
* they are independent readings of the same document, CI runs both, and a disagreement
|
|
33
|
+
* between them surfaces as a failure rather than as silence.
|
|
34
|
+
*/
|
|
35
|
+
export async function lint(opts) {
|
|
36
|
+
const targets = opts.paths.length > 0 ? opts.paths : await defaultPaths(opts.root);
|
|
37
|
+
if (targets.length === 0) {
|
|
38
|
+
err(`${yellow('Nothing to lint.')} Point at a SKILL.md or a skills directory.`);
|
|
39
|
+
return 1;
|
|
40
|
+
}
|
|
41
|
+
const files = [];
|
|
42
|
+
for (const t of targets)
|
|
43
|
+
files.push(...await skillFiles(t));
|
|
44
|
+
if (files.length === 0) {
|
|
45
|
+
err(`${yellow('No SKILL.md found in')} ${targets.join(', ')}`);
|
|
46
|
+
return 1;
|
|
47
|
+
}
|
|
48
|
+
let errors = 0;
|
|
49
|
+
let warnings = 0;
|
|
50
|
+
const parsed = [];
|
|
51
|
+
const perFile = new Map();
|
|
52
|
+
const fileOf = new Map();
|
|
53
|
+
for (const file of files) {
|
|
54
|
+
const text = await readFile(file, 'utf8');
|
|
55
|
+
perFile.set(file, lintSkill(text, file));
|
|
56
|
+
try {
|
|
57
|
+
const skill = parseSkill(text);
|
|
58
|
+
parsed.push(skill);
|
|
59
|
+
fileOf.set(skill.name, file);
|
|
60
|
+
}
|
|
61
|
+
catch {
|
|
62
|
+
// already reported by lintSkill
|
|
63
|
+
}
|
|
64
|
+
}
|
|
65
|
+
// requires and cross-references can only be judged against the whole set
|
|
66
|
+
for (const [name, found] of lintRegistry(parsed)) {
|
|
67
|
+
const file = fileOf.get(name);
|
|
68
|
+
if (!file)
|
|
69
|
+
continue;
|
|
70
|
+
perFile.set(file, [...(perFile.get(file) ?? []), ...found]);
|
|
71
|
+
}
|
|
72
|
+
out();
|
|
73
|
+
for (const file of files) {
|
|
74
|
+
const found = perFile.get(file) ?? [];
|
|
75
|
+
const where = relative(opts.root, file) || file;
|
|
76
|
+
if (found.length === 0) {
|
|
77
|
+
out(` ${green('ok')} ${dim(where)}`);
|
|
78
|
+
continue;
|
|
79
|
+
}
|
|
80
|
+
out(` ${found.some((f) => f.level === 'error') ? red('fail') : yellow('warn')} ${bold(where)}`);
|
|
81
|
+
for (const f of found) {
|
|
82
|
+
if (f.level === 'error')
|
|
83
|
+
errors += 1;
|
|
84
|
+
else
|
|
85
|
+
warnings += 1;
|
|
86
|
+
const at = f.line === undefined ? '' : dim(`:${f.line}`);
|
|
87
|
+
out(` ${f.level === 'error' ? red('error') : yellow('warn ')}${at} ${f.message}`);
|
|
88
|
+
if (f.detail)
|
|
89
|
+
out(` ${dim(f.detail)}`);
|
|
90
|
+
}
|
|
91
|
+
}
|
|
92
|
+
out();
|
|
93
|
+
out(` ${files.length} skill${files.length === 1 ? '' : 's'}, ${errors} error${errors === 1 ? '' : 's'}, ${warnings} warning${warnings === 1 ? '' : 's'}`);
|
|
94
|
+
if (errors === 0 && warnings > 0 && opts.strict !== true) {
|
|
95
|
+
out(` ${dim('warnings do not fail this run,')} ${cyan('--strict')} ${dim('makes them')}`);
|
|
96
|
+
}
|
|
97
|
+
out();
|
|
98
|
+
return errors > 0 || (opts.strict === true && warnings > 0) ? 1 : 0;
|
|
99
|
+
}
|
|
100
|
+
async function defaultPaths(root) {
|
|
101
|
+
for (const candidate of ['skills', '.']) {
|
|
102
|
+
const path = join(root, candidate);
|
|
103
|
+
const found = await skillFiles(path);
|
|
104
|
+
if (found.length > 0)
|
|
105
|
+
return [path];
|
|
106
|
+
}
|
|
107
|
+
return [];
|
|
108
|
+
}
|
|
109
|
+
//# sourceMappingURL=lint.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"lint.js","sourceRoot":"","sources":["../../src/commands/lint.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"list.d.ts","sourceRoot":"","sources":["../../src/commands/list.ts"],"names":[],"mappings":"AAqBA,wBAAsB,IAAI,CAAC,IAAI,EAAE;IAAE,IAAI,EAAE,MAAM,CAAC;IAAC,GAAG,CAAC,EAAE,MAAM,GAAG,SAAS,CAAC;IAAC,OAAO,CAAC,EAAE,OAAO,GAAG,SAAS,CAAA;CAAE,GAAG,OAAO,CAAC,MAAM,CAAC,CAwC3H"}
|
|
@@ -0,0 +1,60 @@
|
|
|
1
|
+
import { drift } from '@skyl/core';
|
|
2
|
+
import { loadRegistry } from "../registry.js";
|
|
3
|
+
import { readInstalled, readLockfile, resolveTarget } from "../install.js";
|
|
4
|
+
import { bold, cyan, dim, out, tokens, yellow } from "../ui.js";
|
|
5
|
+
const LABEL = {
|
|
6
|
+
unchanged: dim,
|
|
7
|
+
'local-edit': yellow,
|
|
8
|
+
'upstream-change': cyan,
|
|
9
|
+
both: yellow,
|
|
10
|
+
missing: yellow,
|
|
11
|
+
};
|
|
12
|
+
const SAYS = {
|
|
13
|
+
unchanged: '',
|
|
14
|
+
'local-edit': 'edited here',
|
|
15
|
+
'upstream-change': 'update available',
|
|
16
|
+
both: 'edited here, and updated upstream',
|
|
17
|
+
missing: 'file is gone',
|
|
18
|
+
};
|
|
19
|
+
export async function list(opts) {
|
|
20
|
+
const lock = await readLockfile(opts.root);
|
|
21
|
+
if (!lock || Object.keys(lock.skills).length === 0) {
|
|
22
|
+
out(`${yellow('Nothing installed.')} Run ${bold('skyl scan')} to see what fits this project.`);
|
|
23
|
+
return 0;
|
|
24
|
+
}
|
|
25
|
+
const target = resolveTarget(undefined, lock);
|
|
26
|
+
let upstream = new Map();
|
|
27
|
+
try {
|
|
28
|
+
const reg = await loadRegistry({ dir: opts.dir, refresh: opts.refresh });
|
|
29
|
+
upstream = new Map(reg.skills.map((s) => [s.name, s]));
|
|
30
|
+
}
|
|
31
|
+
catch {
|
|
32
|
+
// offline is fine: local state is still worth showing, drift just cannot be judged
|
|
33
|
+
}
|
|
34
|
+
out();
|
|
35
|
+
out(` ${bold('Installed')} ${dim(`for ${target.id}, in ${target.dir}`)}`);
|
|
36
|
+
out();
|
|
37
|
+
let words = 0;
|
|
38
|
+
for (const name of Object.keys(lock.skills).sort()) {
|
|
39
|
+
const entry = lock.skills[name];
|
|
40
|
+
const remote = upstream.get(name);
|
|
41
|
+
const onDisk = remote ? await readInstalled(opts.root, target, remote) : undefined;
|
|
42
|
+
const state = upstream.size === 0 ? 'unchanged' : drift(entry, onDisk, remote);
|
|
43
|
+
const note = SAYS[state];
|
|
44
|
+
if (remote)
|
|
45
|
+
words += remote.installableWords;
|
|
46
|
+
out(` ${bold(name.padEnd(22))} ${entry.version.padEnd(8)} ${dim(entry.reason.padEnd(10))} ${LABEL[state](note)}`);
|
|
47
|
+
}
|
|
48
|
+
out();
|
|
49
|
+
if (words > 0)
|
|
50
|
+
out(` ${Object.keys(lock.skills).length} skills, ${tokens(words)}`);
|
|
51
|
+
const stale = Object.keys(lock.skills).some((n) => {
|
|
52
|
+
const r = upstream.get(n);
|
|
53
|
+
return r && r.version !== lock.skills[n].version;
|
|
54
|
+
});
|
|
55
|
+
if (stale)
|
|
56
|
+
out(` ${cyan('skyl add')} ${dim('reinstalls at the current version')}`);
|
|
57
|
+
out();
|
|
58
|
+
return 0;
|
|
59
|
+
}
|
|
60
|
+
//# sourceMappingURL=list.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"list.js","sourceRoot":"","sources":["../../src/commands/list.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
export interface RemoveOptions {
|
|
2
|
+
root: string;
|
|
3
|
+
names: string[];
|
|
4
|
+
dir?: string | undefined;
|
|
5
|
+
refresh?: boolean | undefined;
|
|
6
|
+
yes?: boolean | undefined;
|
|
7
|
+
}
|
|
8
|
+
/**
|
|
9
|
+
* Take a skill back out.
|
|
10
|
+
*
|
|
11
|
+
* Removal refuses to orphan a dependency: if something still installed requires the
|
|
12
|
+
* skill being removed, that other skill is left referring to rules the agent will not
|
|
13
|
+
* have, which is a worse state than either keeping or removing both.
|
|
14
|
+
*/
|
|
15
|
+
export declare function remove(opts: RemoveOptions): Promise<number>;
|
|
16
|
+
//# sourceMappingURL=remove.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"remove.d.ts","sourceRoot":"","sources":["../../src/commands/remove.ts"],"names":[],"mappings":"AAOA,MAAM,WAAW,aAAa;IAC5B,IAAI,EAAE,MAAM,CAAC;IACb,KAAK,EAAE,MAAM,EAAE,CAAC;IAChB,GAAG,CAAC,EAAE,MAAM,GAAG,SAAS,CAAC;IACzB,OAAO,CAAC,EAAE,OAAO,GAAG,SAAS,CAAC;IAC9B,GAAG,CAAC,EAAE,OAAO,GAAG,SAAS,CAAC;CAC3B;AAED;;;;;;GAMG;AACH,wBAAsB,MAAM,CAAC,IAAI,EAAE,aAAa,GAAG,OAAO,CAAC,MAAM,CAAC,CA2DjE"}
|
|
@@ -0,0 +1,73 @@
|
|
|
1
|
+
import { rm } from 'node:fs/promises';
|
|
2
|
+
import { dirname } from 'node:path';
|
|
3
|
+
import { normalise } from '@skyl/core';
|
|
4
|
+
import { pathFor, readLockfile, resolveTarget, writeLockfile } from "../install.js";
|
|
5
|
+
import { loadRegistry } from "../registry.js";
|
|
6
|
+
import { bold, confirm, dim, green, out, red, yellow } from "../ui.js";
|
|
7
|
+
/**
|
|
8
|
+
* Take a skill back out.
|
|
9
|
+
*
|
|
10
|
+
* Removal refuses to orphan a dependency: if something still installed requires the
|
|
11
|
+
* skill being removed, that other skill is left referring to rules the agent will not
|
|
12
|
+
* have, which is a worse state than either keeping or removing both.
|
|
13
|
+
*/
|
|
14
|
+
export async function remove(opts) {
|
|
15
|
+
const lock = await readLockfile(opts.root);
|
|
16
|
+
if (!lock || Object.keys(lock.skills).length === 0) {
|
|
17
|
+
out(`${yellow('Nothing installed.')}`);
|
|
18
|
+
return 1;
|
|
19
|
+
}
|
|
20
|
+
if (opts.names.length === 0) {
|
|
21
|
+
out(`${yellow('Name a skill to remove.')}`);
|
|
22
|
+
return 1;
|
|
23
|
+
}
|
|
24
|
+
const target = resolveTarget(undefined, lock);
|
|
25
|
+
const { skills } = await loadRegistry({ dir: opts.dir, refresh: opts.refresh });
|
|
26
|
+
const byName = new Map(skills.map((s) => [s.name, s]));
|
|
27
|
+
const installed = new Set(Object.keys(lock.skills));
|
|
28
|
+
const asked = normalise(skills.filter((s) => installed.has(s.name)), opts.names);
|
|
29
|
+
const going = new Set(asked);
|
|
30
|
+
const orphaned = [];
|
|
31
|
+
for (const name of installed) {
|
|
32
|
+
if (going.has(name))
|
|
33
|
+
continue;
|
|
34
|
+
for (const dep of byName.get(name)?.requires ?? []) {
|
|
35
|
+
if (going.has(dep))
|
|
36
|
+
orphaned.push(`${name} requires ${dep}`);
|
|
37
|
+
}
|
|
38
|
+
}
|
|
39
|
+
if (orphaned.length > 0) {
|
|
40
|
+
out(` ${red('Still required.')}`);
|
|
41
|
+
for (const line of orphaned)
|
|
42
|
+
out(` ${dim(line)}`);
|
|
43
|
+
out();
|
|
44
|
+
out(` ${dim('Remove those first, or keep this one.')}`);
|
|
45
|
+
return 1;
|
|
46
|
+
}
|
|
47
|
+
out();
|
|
48
|
+
for (const name of asked)
|
|
49
|
+
out(` ${bold(name.padEnd(22))} ${red('remove')}`);
|
|
50
|
+
out();
|
|
51
|
+
if (!(await confirm(' Delete them?', opts.yes === true))) {
|
|
52
|
+
out(` ${dim('Nothing deleted.')}`);
|
|
53
|
+
return 1;
|
|
54
|
+
}
|
|
55
|
+
const skills2 = { ...lock.skills };
|
|
56
|
+
for (const name of asked) {
|
|
57
|
+
const skill = byName.get(name);
|
|
58
|
+
if (skill) {
|
|
59
|
+
const file = pathFor(opts.root, target, skill);
|
|
60
|
+
await rm(file, { force: true });
|
|
61
|
+
// claude puts each skill in its own directory, which is now empty
|
|
62
|
+
if (target.fileFor(name).includes('/'))
|
|
63
|
+
await rm(dirname(file), { recursive: true, force: true });
|
|
64
|
+
}
|
|
65
|
+
delete skills2[name];
|
|
66
|
+
}
|
|
67
|
+
await writeLockfile(opts.root, { ...lock, skills: skills2 });
|
|
68
|
+
out();
|
|
69
|
+
out(` ${green('Removed.')} ${dim(`${asked.length} gone, ${Object.keys(skills2).length} left`)}`);
|
|
70
|
+
out();
|
|
71
|
+
return 0;
|
|
72
|
+
}
|
|
73
|
+
//# sourceMappingURL=remove.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"remove.js","sourceRoot":"","sources":["../../src/commands/remove.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,EAAE,EAAE,MAAM,kBAAkB,CAAC;AACtC,OAAO,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AACpC,OAAO,EAAE,SAAS,EAAE,MAAM,YAAY,CAAC;AACvC,OAAO,EAAE,OAAO,EAAE,YAAY,EAAE,aAAa,EAAE,aAAa,EAAE,MAAM,eAAe,CAAC;AACpF,OAAO,EAAE,YAAY,EAAE,MAAM,gBAAgB,CAAC;AAC9C,OAAO,EAAE,IAAI,EAAE,OAAO,EAAE,GAAG,EAAE,KAAK,EAAE,GAAG,EAAE,GAAG,EAAE,MAAM,EAAE,MAAM,UAAU,CAAC;AAUvE;;;;;;GAMG;AACH,MAAM,CAAC,KAAK,UAAU,MAAM,CAAC,IAAmB;IAC9C,MAAM,IAAI,GAAG,MAAM,YAAY,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;IAC3C,IAAI,CAAC,IAAI,IAAI,MAAM,CAAC,IAAI,CAAC,IAAI,CAAC,MAAM,CAAC,CAAC,MAAM,KAAK,CAAC,EAAE,CAAC;QACnD,GAAG,CAAC,GAAG,MAAM,CAAC,oBAAoB,CAAC,EAAE,CAAC,CAAC;QACvC,OAAO,CAAC,CAAC;IACX,CAAC;IACD,IAAI,IAAI,CAAC,KAAK,CAAC,MAAM,KAAK,CAAC,EAAE,CAAC;QAC5B,GAAG,CAAC,GAAG,MAAM,CAAC,yBAAyB,CAAC,EAAE,CAAC,CAAC;QAC5C,OAAO,CAAC,CAAC;IACX,CAAC;IAED,MAAM,MAAM,GAAG,aAAa,CAAC,SAAS,EAAE,IAAI,CAAC,CAAC;IAC9C,MAAM,EAAE,MAAM,EAAE,GAAG,MAAM,YAAY,CAAC,EAAE,GAAG,EAAE,IAAI,CAAC,GAAG,EAAE,OAAO,EAAE,IAAI,CAAC,OAAO,EAAE,CAAC,CAAC;IAChF,MAAM,MAAM,GAAG,IAAI,GAAG,CAAC,MAAM,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,CAAC,IAAI,EAAE,CAAC,CAAC,CAAC,CAAC,CAAC;IACvD,MAAM,SAAS,GAAG,IAAI,GAAG,CAAC,MAAM,CAAC,IAAI,CAAC,IAAI,CAAC,MAAM,CAAC,CAAC,CAAC;IAEpD,MAAM,KAAK,GAAG,SAAS,CAAC,MAAM,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,SAAS,CAAC,GAAG,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,EAAE,IAAI,CAAC,KAAK,CAAC,CAAC;IACjF,MAAM,KAAK,GAAG,IAAI,GAAG,CAAC,KAAK,CAAC,CAAC;IAE7B,MAAM,QAAQ,GAAa,EAAE,CAAC;IAC9B,KAAK,MAAM,IAAI,IAAI,SAAS,EAAE,CAAC;QAC7B,IAAI,KAAK,CAAC,GAAG,CAAC,IAAI,CAAC;YAAE,SAAS;QAC9B,KAAK,MAAM,GAAG,IAAI,MAAM,CAAC,GAAG,CAAC,IAAI,CAAC,EAAE,QAAQ,IAAI,EAAE,EAAE,CAAC;YACnD,IAAI,KAAK,CAAC,GAAG,CAAC,GAAG,CAAC;gBAAE,QAAQ,CAAC,IAAI,CAAC,GAAG,IAAI,aAAa,GAAG,EAAE,CAAC,CAAC;QAC/D,CAAC;IACH,CAAC;IACD,IAAI,QAAQ,CAAC,MAAM,GAAG,CAAC,EAAE,CAAC;QACxB,GAAG,CAAC,KAAK,GAAG,CAAC,iBAAiB,CAAC,EAAE,CAAC,CAAC;QACnC,KAAK,MAAM,IAAI,IAAI,QAAQ;YAAE,GAAG,CAAC,OAAO,GAAG,CAAC,IAAI,CAAC,EAAE,CAAC,CAAC;QACrD,GAAG,EAAE,CAAC;QACN,GAAG,CAAC,KAAK,GAAG,CAAC,uCAAuC,CAAC,EAAE,CAAC,CAAC;QACzD,OAAO,CAAC,CAAC;IACX,CAAC;IAED,GAAG,EAAE,CAAC;IACN,KAAK,MAAM,IAAI,IAAI,KAAK;QAAE,GAAG,CAAC,OAAO,IAAI,CAAC,IAAI,CAAC,MAAM,CAAC,EAAE,CAAC,CAAC,IAAI,GAAG,CAAC,QAAQ,CAAC,EAAE,CAAC,CAAC;IAC/E,GAAG,EAAE,CAAC;IACN,IAAI,CAAC,CAAC,MAAM,OAAO,CAAC,gBAAgB,EAAE,IAAI,CAAC,GAAG,KAAK,IAAI,CAAC,CAAC,EAAE,CAAC;QAC1D,GAAG,CAAC,KAAK,GAAG,CAAC,kBAAkB,CAAC,EAAE,CAAC,CAAC;QACpC,OAAO,CAAC,CAAC;IACX,CAAC;IAED,MAAM,OAAO,GAAG,EAAE,GAAG,IAAI,CAAC,MAAM,EAAE,CAAC;IACnC,KAAK,MAAM,IAAI,IAAI,KAAK,EAAE,CAAC;QACzB,MAAM,KAAK,GAAG,MAAM,CAAC,GAAG,CAAC,IAAI,CAAC,CAAC;QAC/B,IAAI,KAAK,EAAE,CAAC;YACV,MAAM,IAAI,GAAG,OAAO,CAAC,IAAI,CAAC,IAAI,EAAE,MAAM,EAAE,KAAK,CAAC,CAAC;YAC/C,MAAM,EAAE,CAAC,IAAI,EAAE,EAAE,KAAK,EAAE,IAAI,EAAE,CAAC,CAAC;YAChC,kEAAkE;YAClE,IAAI,MAAM,CAAC,OAAO,CAAC,IAAI,CAAC,CAAC,QAAQ,CAAC,GAAG,CAAC;gBAAE,MAAM,EAAE,CAAC,OAAO,CAAC,IAAI,CAAC,EAAE,EAAE,SAAS,EAAE,IAAI,EAAE,KAAK,EAAE,IAAI,EAAE,CAAC,CAAC;QACpG,CAAC;QACD,OAAO,OAAO,CAAC,IAAI,CAAC,CAAC;IACvB,CAAC;IACD,MAAM,aAAa,CAAC,IAAI,CAAC,IAAI,EAAE,EAAE,GAAG,IAAI,EAAE,MAAM,EAAE,OAAO,EAAE,CAAC,CAAC;IAE7D,GAAG,EAAE,CAAC;IACN,GAAG,CAAC,KAAK,KAAK,CAAC,UAAU,CAAC,IAAI,GAAG,CAAC,GAAG,KAAK,CAAC,MAAM,UAAU,MAAM,CAAC,IAAI,CAAC,OAAO,CAAC,CAAC,MAAM,OAAO,CAAC,EAAE,CAAC,CAAC;IAClG,GAAG,EAAE,CAAC;IACN,OAAO,CAAC,CAAC;AACX,CAAC"}
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
import { type Skill } from '@skyl/core';
|
|
2
|
+
export interface ScanOptions {
|
|
3
|
+
root: string;
|
|
4
|
+
dir?: string | undefined;
|
|
5
|
+
refresh?: boolean | undefined;
|
|
6
|
+
json?: boolean | undefined;
|
|
7
|
+
}
|
|
8
|
+
export declare function scan(opts: ScanOptions): Promise<number>;
|
|
9
|
+
export type { Skill };
|
|
10
|
+
//# sourceMappingURL=scan.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"scan.d.ts","sourceRoot":"","sources":["../../src/commands/scan.ts"],"names":[],"mappings":"AAAA,OAAO,EAA8B,KAAK,KAAK,EAAE,MAAM,YAAY,CAAC;AAMpE,MAAM,WAAW,WAAW;IAC1B,IAAI,EAAE,MAAM,CAAC;IACb,GAAG,CAAC,EAAE,MAAM,GAAG,SAAS,CAAC;IACzB,OAAO,CAAC,EAAE,OAAO,GAAG,SAAS,CAAC;IAC9B,IAAI,CAAC,EAAE,OAAO,GAAG,SAAS,CAAC;CAC5B;AAED,wBAAsB,IAAI,CAAC,IAAI,EAAE,WAAW,GAAG,OAAO,CAAC,MAAM,CAAC,CAyD7D;AAED,YAAY,EAAE,KAAK,EAAE,CAAC"}
|
|
@@ -0,0 +1,60 @@
|
|
|
1
|
+
import { detect, resolve, unmatched } from '@skyl/core';
|
|
2
|
+
import { scanProject } from "../scan.js";
|
|
3
|
+
import { loadRegistry } from "../registry.js";
|
|
4
|
+
import { readLockfile, resolveTarget } from "../install.js";
|
|
5
|
+
import { bold, cyan, dim, green, out, tokens, yellow } from "../ui.js";
|
|
6
|
+
export async function scan(opts) {
|
|
7
|
+
const { skills } = await loadRegistry({ dir: opts.dir, refresh: opts.refresh });
|
|
8
|
+
const signals = await scanProject(opts.root);
|
|
9
|
+
const matched = detect(skills, signals);
|
|
10
|
+
if (matched.length === 0) {
|
|
11
|
+
out(`${yellow('Nothing detected.')} No skill in the registry matches this project.`);
|
|
12
|
+
out(dim(' Skyl currently covers Android. If this is an Android project, please open an issue.'));
|
|
13
|
+
return 0;
|
|
14
|
+
}
|
|
15
|
+
const chosen = resolve(skills, matched.map((m) => m.skill));
|
|
16
|
+
const lock = await readLockfile(opts.root);
|
|
17
|
+
const target = resolveTarget(undefined, lock);
|
|
18
|
+
const installed = new Set(Object.keys(lock?.skills ?? {}));
|
|
19
|
+
if (opts.json) {
|
|
20
|
+
out(JSON.stringify({
|
|
21
|
+
detected: matched,
|
|
22
|
+
install: chosen.map((s) => ({ name: s.name, version: s.version, words: s.installableWords, installed: installed.has(s.name) })),
|
|
23
|
+
target: target.id,
|
|
24
|
+
}, null, 2));
|
|
25
|
+
return 0;
|
|
26
|
+
}
|
|
27
|
+
const evidence = new Map();
|
|
28
|
+
for (const m of matched)
|
|
29
|
+
evidence.set(m.skill, m.on.map((o) => o.value));
|
|
30
|
+
out();
|
|
31
|
+
out(` ${bold('Detected')} ${dim(`in ${opts.root}`)}`);
|
|
32
|
+
out();
|
|
33
|
+
for (const skill of chosen) {
|
|
34
|
+
const why = evidence.get(skill.name);
|
|
35
|
+
const mark = installed.has(skill.name) ? dim('installed') : green('new');
|
|
36
|
+
const reason = why?.length ? why[0] : skill.axis === 'core' ? `every ${skill.family} project` : 'required';
|
|
37
|
+
out(` ${bold(skill.name.padEnd(22))} ${mark.padEnd(18)} ${dim(reason)}`);
|
|
38
|
+
}
|
|
39
|
+
const rest = unmatched(skills, matched).filter((s) => !chosen.some((c) => c.name === s.name));
|
|
40
|
+
if (rest.length > 0) {
|
|
41
|
+
out();
|
|
42
|
+
out(` ${dim('Considered and not detected')}`);
|
|
43
|
+
for (const s of rest)
|
|
44
|
+
out(` ${dim(s.name)}`);
|
|
45
|
+
}
|
|
46
|
+
const fresh = chosen.filter((s) => !installed.has(s.name));
|
|
47
|
+
const words = fresh.reduce((n, s) => n + s.installableWords, 0);
|
|
48
|
+
out();
|
|
49
|
+
if (fresh.length === 0) {
|
|
50
|
+
out(` ${green('Up to date.')} ${dim(`${chosen.length} skills installed for ${target.id}.`)}`);
|
|
51
|
+
}
|
|
52
|
+
else {
|
|
53
|
+
out(` ${fresh.length} to install, ${tokens(words)} ${dim(`into ${target.dir}`)}`);
|
|
54
|
+
out();
|
|
55
|
+
out(` ${cyan(`skyl add ${fresh.map((s) => s.name).join(' ')}`)}`);
|
|
56
|
+
}
|
|
57
|
+
out();
|
|
58
|
+
return 0;
|
|
59
|
+
}
|
|
60
|
+
//# sourceMappingURL=scan.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"scan.js","sourceRoot":"","sources":["../../src/commands/scan.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
export interface UpdateOptions {
|
|
2
|
+
root: string;
|
|
3
|
+
names?: string[];
|
|
4
|
+
dir?: string | undefined;
|
|
5
|
+
refresh?: boolean | undefined;
|
|
6
|
+
yes?: boolean | undefined;
|
|
7
|
+
force?: boolean | undefined;
|
|
8
|
+
showDiff?: boolean | undefined;
|
|
9
|
+
}
|
|
10
|
+
export declare function update(opts: UpdateOptions): Promise<number>;
|
|
11
|
+
//# sourceMappingURL=update.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"update.d.ts","sourceRoot":"","sources":["../../src/commands/update.ts"],"names":[],"mappings":"AAOA,MAAM,WAAW,aAAa;IAC5B,IAAI,EAAE,MAAM,CAAC;IACb,KAAK,CAAC,EAAE,MAAM,EAAE,CAAC;IACjB,GAAG,CAAC,EAAE,MAAM,GAAG,SAAS,CAAC;IACzB,OAAO,CAAC,EAAE,OAAO,GAAG,SAAS,CAAC;IAC9B,GAAG,CAAC,EAAE,OAAO,GAAG,SAAS,CAAC;IAC1B,KAAK,CAAC,EAAE,OAAO,GAAG,SAAS,CAAC;IAC5B,QAAQ,CAAC,EAAE,OAAO,GAAG,SAAS,CAAC;CAChC;AAaD,wBAAsB,MAAM,CAAC,IAAI,EAAE,aAAa,GAAG,OAAO,CAAC,MAAM,CAAC,CA6GjE"}
|