@sporesec/arcana 2.3.1 → 3.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/cli.d.ts +0 -1
- package/dist/cli.js +140 -10
- package/dist/command-registry.d.ts +10 -0
- package/dist/command-registry.js +65 -0
- package/dist/commands/audit.d.ts +0 -1
- package/dist/commands/audit.js +16 -6
- package/dist/commands/benchmark.d.ts +4 -0
- package/dist/commands/benchmark.js +178 -0
- package/dist/commands/clean.d.ts +2 -1
- package/dist/commands/clean.js +198 -47
- package/dist/commands/compact.d.ts +6 -0
- package/dist/commands/compact.js +239 -0
- package/dist/commands/completions.d.ts +3 -0
- package/dist/commands/completions.js +104 -0
- package/dist/commands/config.d.ts +0 -1
- package/dist/commands/config.js +15 -6
- package/dist/commands/create.d.ts +0 -1
- package/dist/commands/create.js +1 -1
- package/dist/commands/diff.d.ts +4 -0
- package/dist/commands/diff.js +166 -0
- package/dist/commands/doctor.d.ts +0 -1
- package/dist/commands/doctor.js +153 -24
- package/dist/commands/export-cmd.d.ts +4 -0
- package/dist/commands/export-cmd.js +66 -0
- package/dist/commands/import-cmd.d.ts +4 -0
- package/dist/commands/import-cmd.js +131 -0
- package/dist/commands/info.d.ts +0 -1
- package/dist/commands/info.js +29 -4
- package/dist/commands/init.d.ts +0 -1
- package/dist/commands/init.js +156 -117
- package/dist/commands/install.d.ts +1 -1
- package/dist/commands/install.js +118 -205
- package/dist/commands/list.d.ts +0 -1
- package/dist/commands/list.js +12 -4
- package/dist/commands/lock.d.ts +4 -0
- package/dist/commands/lock.js +171 -0
- package/dist/commands/optimize.d.ts +3 -0
- package/dist/commands/optimize.js +356 -0
- package/dist/commands/outdated.d.ts +4 -0
- package/dist/commands/outdated.js +159 -0
- package/dist/commands/profile.d.ts +3 -0
- package/dist/commands/profile.js +274 -0
- package/dist/commands/providers.d.ts +0 -1
- package/dist/commands/providers.js +1 -4
- package/dist/commands/recommend.d.ts +5 -0
- package/dist/commands/recommend.js +96 -0
- package/dist/commands/scan.d.ts +0 -1
- package/dist/commands/scan.js +13 -7
- package/dist/commands/search.d.ts +2 -1
- package/dist/commands/search.js +32 -9
- package/dist/commands/stats.d.ts +0 -1
- package/dist/commands/stats.js +83 -16
- package/dist/commands/team.d.ts +3 -0
- package/dist/commands/team.js +291 -0
- package/dist/commands/uninstall.d.ts +0 -1
- package/dist/commands/uninstall.js +18 -4
- package/dist/commands/update.d.ts +0 -1
- package/dist/commands/update.js +155 -155
- package/dist/commands/validate.d.ts +0 -1
- package/dist/commands/validate.js +14 -6
- package/dist/commands/verify.d.ts +4 -0
- package/dist/commands/verify.js +116 -0
- package/dist/constants.d.ts +10 -0
- package/dist/constants.js +13 -0
- package/dist/index.d.ts +0 -1
- package/dist/index.js +0 -1
- package/dist/interactive/browse.d.ts +4 -0
- package/dist/interactive/browse.js +103 -0
- package/dist/interactive/categories.d.ts +4 -0
- package/dist/interactive/categories.js +87 -0
- package/dist/interactive/health.d.ts +1 -0
- package/dist/interactive/health.js +57 -0
- package/dist/interactive/helpers.d.ts +11 -0
- package/dist/interactive/helpers.js +66 -0
- package/dist/interactive/index.d.ts +1 -0
- package/dist/interactive/index.js +1 -0
- package/dist/interactive/manage.d.ts +2 -0
- package/dist/interactive/manage.js +187 -0
- package/dist/interactive/menu.d.ts +1 -0
- package/dist/interactive/menu.js +107 -0
- package/dist/interactive/search.d.ts +2 -0
- package/dist/interactive/search.js +66 -0
- package/dist/interactive/setup.d.ts +2 -0
- package/dist/interactive/setup.js +48 -0
- package/dist/interactive/skill-detail.d.ts +5 -0
- package/dist/interactive/skill-detail.js +126 -0
- package/dist/interactive.d.ts +0 -1
- package/dist/interactive.js +89 -66
- package/dist/providers/arcana.d.ts +0 -1
- package/dist/providers/arcana.js +0 -1
- package/dist/providers/base.d.ts +0 -1
- package/dist/providers/base.js +0 -1
- package/dist/providers/github.d.ts +0 -1
- package/dist/providers/github.js +8 -3
- package/dist/registry.d.ts +0 -1
- package/dist/registry.js +1 -4
- package/dist/types.d.ts +10 -1
- package/dist/types.js +0 -1
- package/dist/utils/atomic.d.ts +0 -1
- package/dist/utils/atomic.js +3 -2
- package/dist/utils/cache.d.ts +0 -1
- package/dist/utils/cache.js +3 -2
- package/dist/utils/config.d.ts +2 -1
- package/dist/utils/config.js +30 -5
- package/dist/utils/conflict-check.d.ts +8 -0
- package/dist/utils/conflict-check.js +72 -0
- package/dist/utils/errors.d.ts +0 -1
- package/dist/utils/errors.js +0 -1
- package/dist/utils/frontmatter.d.ts +0 -1
- package/dist/utils/frontmatter.js +37 -10
- package/dist/utils/fs.d.ts +19 -1
- package/dist/utils/fs.js +105 -8
- package/dist/utils/help.d.ts +0 -1
- package/dist/utils/help.js +15 -28
- package/dist/utils/history.d.ts +0 -1
- package/dist/utils/history.js +0 -1
- package/dist/utils/http.d.ts +0 -1
- package/dist/utils/http.js +14 -5
- package/dist/utils/install-core.d.ts +48 -0
- package/dist/utils/install-core.js +108 -0
- package/dist/utils/integrity.d.ts +17 -0
- package/dist/utils/integrity.js +84 -0
- package/dist/utils/parallel.d.ts +0 -1
- package/dist/utils/parallel.js +0 -1
- package/dist/utils/project-context.d.ts +19 -0
- package/dist/utils/project-context.js +283 -0
- package/dist/utils/scanner.d.ts +0 -1
- package/dist/utils/scanner.js +138 -10
- package/dist/utils/scoring.d.ts +10 -0
- package/dist/utils/scoring.js +84 -0
- package/dist/utils/ui.d.ts +0 -1
- package/dist/utils/ui.js +11 -4
- package/dist/utils/validate.d.ts +0 -1
- package/dist/utils/validate.js +4 -1
- package/package.json +19 -7
- package/dist/cli.d.ts.map +0 -1
- package/dist/cli.js.map +0 -1
- package/dist/commands/audit.d.ts.map +0 -1
- package/dist/commands/audit.js.map +0 -1
- package/dist/commands/audit.test.d.ts +0 -2
- package/dist/commands/audit.test.d.ts.map +0 -1
- package/dist/commands/audit.test.js +0 -217
- package/dist/commands/audit.test.js.map +0 -1
- package/dist/commands/clean.d.ts.map +0 -1
- package/dist/commands/clean.js.map +0 -1
- package/dist/commands/config.d.ts.map +0 -1
- package/dist/commands/config.js.map +0 -1
- package/dist/commands/create.d.ts.map +0 -1
- package/dist/commands/create.js.map +0 -1
- package/dist/commands/doctor.d.ts.map +0 -1
- package/dist/commands/doctor.js.map +0 -1
- package/dist/commands/info.d.ts.map +0 -1
- package/dist/commands/info.js.map +0 -1
- package/dist/commands/init.d.ts.map +0 -1
- package/dist/commands/init.js.map +0 -1
- package/dist/commands/install.d.ts.map +0 -1
- package/dist/commands/install.js.map +0 -1
- package/dist/commands/list.d.ts.map +0 -1
- package/dist/commands/list.js.map +0 -1
- package/dist/commands/providers.d.ts.map +0 -1
- package/dist/commands/providers.js.map +0 -1
- package/dist/commands/scan.d.ts.map +0 -1
- package/dist/commands/scan.js.map +0 -1
- package/dist/commands/search.d.ts.map +0 -1
- package/dist/commands/search.js.map +0 -1
- package/dist/commands/stats.d.ts.map +0 -1
- package/dist/commands/stats.js.map +0 -1
- package/dist/commands/uninstall.d.ts.map +0 -1
- package/dist/commands/uninstall.js.map +0 -1
- package/dist/commands/update.d.ts.map +0 -1
- package/dist/commands/update.js.map +0 -1
- package/dist/commands/validate.d.ts.map +0 -1
- package/dist/commands/validate.js.map +0 -1
- package/dist/index.d.ts.map +0 -1
- package/dist/index.js.map +0 -1
- package/dist/interactive.d.ts.map +0 -1
- package/dist/interactive.js.map +0 -1
- package/dist/providers/arcana.d.ts.map +0 -1
- package/dist/providers/arcana.js.map +0 -1
- package/dist/providers/base.d.ts.map +0 -1
- package/dist/providers/base.js.map +0 -1
- package/dist/providers/github.d.ts.map +0 -1
- package/dist/providers/github.js.map +0 -1
- package/dist/registry.d.ts.map +0 -1
- package/dist/registry.js.map +0 -1
- package/dist/types.d.ts.map +0 -1
- package/dist/types.js.map +0 -1
- package/dist/utils/atomic.d.ts.map +0 -1
- package/dist/utils/atomic.js.map +0 -1
- package/dist/utils/atomic.test.d.ts +0 -2
- package/dist/utils/atomic.test.d.ts.map +0 -1
- package/dist/utils/atomic.test.js +0 -31
- package/dist/utils/atomic.test.js.map +0 -1
- package/dist/utils/cache.d.ts.map +0 -1
- package/dist/utils/cache.js.map +0 -1
- package/dist/utils/config.d.ts.map +0 -1
- package/dist/utils/config.js.map +0 -1
- package/dist/utils/config.test.d.ts +0 -2
- package/dist/utils/config.test.d.ts.map +0 -1
- package/dist/utils/config.test.js +0 -38
- package/dist/utils/config.test.js.map +0 -1
- package/dist/utils/errors.d.ts.map +0 -1
- package/dist/utils/errors.js.map +0 -1
- package/dist/utils/frontmatter.d.ts.map +0 -1
- package/dist/utils/frontmatter.js.map +0 -1
- package/dist/utils/frontmatter.test.d.ts +0 -2
- package/dist/utils/frontmatter.test.d.ts.map +0 -1
- package/dist/utils/frontmatter.test.js +0 -152
- package/dist/utils/frontmatter.test.js.map +0 -1
- package/dist/utils/fs.d.ts.map +0 -1
- package/dist/utils/fs.js.map +0 -1
- package/dist/utils/fs.test.d.ts +0 -2
- package/dist/utils/fs.test.d.ts.map +0 -1
- package/dist/utils/fs.test.js +0 -145
- package/dist/utils/fs.test.js.map +0 -1
- package/dist/utils/help.d.ts.map +0 -1
- package/dist/utils/help.js.map +0 -1
- package/dist/utils/help.test.d.ts +0 -2
- package/dist/utils/help.test.d.ts.map +0 -1
- package/dist/utils/help.test.js +0 -66
- package/dist/utils/help.test.js.map +0 -1
- package/dist/utils/history.d.ts.map +0 -1
- package/dist/utils/history.js.map +0 -1
- package/dist/utils/http.d.ts.map +0 -1
- package/dist/utils/http.js.map +0 -1
- package/dist/utils/http.test.d.ts +0 -2
- package/dist/utils/http.test.d.ts.map +0 -1
- package/dist/utils/http.test.js +0 -55
- package/dist/utils/http.test.js.map +0 -1
- package/dist/utils/parallel.d.ts.map +0 -1
- package/dist/utils/parallel.js.map +0 -1
- package/dist/utils/scanner.d.ts.map +0 -1
- package/dist/utils/scanner.js.map +0 -1
- package/dist/utils/ui.d.ts.map +0 -1
- package/dist/utils/ui.js.map +0 -1
- package/dist/utils/ui.test.d.ts +0 -2
- package/dist/utils/ui.test.d.ts.map +0 -1
- package/dist/utils/ui.test.js +0 -31
- package/dist/utils/ui.test.js.map +0 -1
- package/dist/utils/validate.d.ts.map +0 -1
- package/dist/utils/validate.js.map +0 -1
package/dist/commands/install.js
CHANGED
|
@@ -1,47 +1,12 @@
|
|
|
1
1
|
import * as p from "@clack/prompts";
|
|
2
2
|
import chalk from "chalk";
|
|
3
3
|
import { printErrorWithHint } from "../utils/ui.js";
|
|
4
|
-
import {
|
|
4
|
+
import { isSkillInstalled } from "../utils/fs.js";
|
|
5
5
|
import { getProvider, getProviders } from "../registry.js";
|
|
6
6
|
import { loadConfig } from "../utils/config.js";
|
|
7
7
|
import { renderBanner } from "../utils/help.js";
|
|
8
8
|
import { validateSlug } from "../utils/validate.js";
|
|
9
|
-
import {
|
|
10
|
-
/**
|
|
11
|
-
* Scan fetched skill files for security threats before installing.
|
|
12
|
-
* Returns true if install should proceed, false to block.
|
|
13
|
-
*/
|
|
14
|
-
function preInstallScan(skillName, files, force) {
|
|
15
|
-
const skillMd = files.find(f => f.path.endsWith("SKILL.md"));
|
|
16
|
-
if (!skillMd)
|
|
17
|
-
return true;
|
|
18
|
-
const issues = scanSkillContent(skillMd.content);
|
|
19
|
-
if (issues.length === 0)
|
|
20
|
-
return true;
|
|
21
|
-
const critical = issues.filter(i => i.level === "critical");
|
|
22
|
-
const high = issues.filter(i => i.level === "high");
|
|
23
|
-
if (critical.length > 0) {
|
|
24
|
-
p.log.error(`Security scan blocked ${chalk.bold(skillName)}:`);
|
|
25
|
-
for (const issue of critical) {
|
|
26
|
-
p.log.error(` [CRIT] ${issue.category}: ${issue.detail} (line ${issue.line})`);
|
|
27
|
-
}
|
|
28
|
-
for (const issue of high) {
|
|
29
|
-
p.log.warn(` [HIGH] ${issue.category}: ${issue.detail} (line ${issue.line})`);
|
|
30
|
-
}
|
|
31
|
-
if (!force) {
|
|
32
|
-
p.log.info(chalk.dim("Use --force to install anyway (not recommended)."));
|
|
33
|
-
return false;
|
|
34
|
-
}
|
|
35
|
-
p.log.warn("Installing despite security issues (--force).");
|
|
36
|
-
}
|
|
37
|
-
else if (high.length > 0) {
|
|
38
|
-
p.log.warn(`Security warnings for ${chalk.bold(skillName)}:`);
|
|
39
|
-
for (const issue of high) {
|
|
40
|
-
p.log.warn(` [HIGH] ${issue.category}: ${issue.detail} (line ${issue.line})`);
|
|
41
|
-
}
|
|
42
|
-
}
|
|
43
|
-
return true;
|
|
44
|
-
}
|
|
9
|
+
import { installOneCore, sizeWarning, canInstall, detectProviderChange } from "../utils/install-core.js";
|
|
45
10
|
export async function installCommand(skillNames, opts) {
|
|
46
11
|
if (opts.json) {
|
|
47
12
|
return installJson(skillNames, opts);
|
|
@@ -62,16 +27,16 @@ export async function installCommand(skillNames, opts) {
|
|
|
62
27
|
process.exit(1);
|
|
63
28
|
}
|
|
64
29
|
if (opts.all) {
|
|
65
|
-
await installAllInteractive(providers, opts.dryRun, opts.force);
|
|
30
|
+
await installAllInteractive(providers, opts.dryRun, opts.force, opts.noCheck);
|
|
66
31
|
}
|
|
67
32
|
else if (skillNames.length === 1) {
|
|
68
|
-
await installOneInteractive(skillNames[0], providers[0], opts.dryRun, opts.force);
|
|
33
|
+
await installOneInteractive(skillNames[0], providers[0], opts.dryRun, opts.force, opts.noCheck);
|
|
69
34
|
}
|
|
70
35
|
else {
|
|
71
|
-
await
|
|
36
|
+
await installBatchInteractive(skillNames, providers[0], opts.dryRun, opts.force, opts.noCheck);
|
|
72
37
|
}
|
|
73
38
|
}
|
|
74
|
-
async function installOneInteractive(skillName, provider, dryRun, force) {
|
|
39
|
+
async function installOneInteractive(skillName, provider, dryRun, force, noCheck) {
|
|
75
40
|
p.intro(chalk.bold("Install skill"));
|
|
76
41
|
try {
|
|
77
42
|
validateSlug(skillName, "skill name");
|
|
@@ -80,20 +45,20 @@ async function installOneInteractive(skillName, provider, dryRun, force) {
|
|
|
80
45
|
p.cancel(err instanceof Error ? err.message : "Invalid skill name");
|
|
81
46
|
process.exit(1);
|
|
82
47
|
}
|
|
83
|
-
|
|
48
|
+
const check = canInstall(skillName, force);
|
|
49
|
+
if (!check.proceed) {
|
|
84
50
|
if (dryRun) {
|
|
85
51
|
p.log.info(`${skillName} is already installed.`);
|
|
86
52
|
p.outro("Dry run complete.");
|
|
87
53
|
return;
|
|
88
54
|
}
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
const
|
|
94
|
-
if (
|
|
95
|
-
p.log.warn(
|
|
96
|
-
}
|
|
55
|
+
p.cancel(check.reason);
|
|
56
|
+
process.exit(0);
|
|
57
|
+
}
|
|
58
|
+
if (isSkillInstalled(skillName) && force) {
|
|
59
|
+
const change = detectProviderChange(skillName, provider.name);
|
|
60
|
+
if (change)
|
|
61
|
+
p.log.warn(change);
|
|
97
62
|
p.log.warn(`${skillName} is already installed. Reinstalling...`);
|
|
98
63
|
}
|
|
99
64
|
if (dryRun) {
|
|
@@ -102,40 +67,38 @@ async function installOneInteractive(skillName, provider, dryRun, force) {
|
|
|
102
67
|
return;
|
|
103
68
|
}
|
|
104
69
|
const spin = p.spinner();
|
|
105
|
-
spin.start(`
|
|
70
|
+
spin.start(`Installing ${chalk.bold(skillName)} from ${provider.name}...`);
|
|
106
71
|
try {
|
|
107
|
-
const
|
|
108
|
-
|
|
109
|
-
|
|
72
|
+
const result = await installOneCore(skillName, provider, { force, noCheck });
|
|
73
|
+
if (!result.success) {
|
|
74
|
+
spin.stop("Blocked.");
|
|
75
|
+
if (result.scanBlocked) {
|
|
76
|
+
p.log.error(`Security scan blocked ${chalk.bold(skillName)}`);
|
|
77
|
+
p.log.info(chalk.dim("Use --force to install anyway (not recommended)."));
|
|
78
|
+
}
|
|
79
|
+
else if (result.conflictBlocked) {
|
|
80
|
+
p.log.error(`Conflict detected for ${chalk.bold(skillName)}`);
|
|
81
|
+
p.log.info("Use --force to install anyway or --no-check to skip conflict detection.");
|
|
82
|
+
}
|
|
110
83
|
process.exit(1);
|
|
111
84
|
}
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
writeSkillMeta(skillName, {
|
|
117
|
-
version: remote?.version ?? "0.0.0",
|
|
118
|
-
installedAt: new Date().toISOString(),
|
|
119
|
-
source: provider.name,
|
|
120
|
-
description: remote?.description,
|
|
121
|
-
fileCount: files.length,
|
|
122
|
-
sizeBytes: files.reduce((s, f) => s + f.content.length, 0),
|
|
123
|
-
});
|
|
124
|
-
const sizeKB = files.reduce((s, f) => s + f.content.length, 0) / 1024;
|
|
125
|
-
spin2.stop(`Installed ${chalk.bold(skillName)} (${files.length} files, ${sizeKB.toFixed(1)} KB)`);
|
|
126
|
-
if (sizeKB > 50) {
|
|
127
|
-
p.log.warn(`Large skill (${sizeKB.toFixed(0)} KB, ~${Math.round(sizeKB * 256)} tokens). May use significant context.`);
|
|
85
|
+
spin.stop(`Installed ${chalk.bold(skillName)} (${result.files?.length ?? 0} files, ${result.sizeKB?.toFixed(1) ?? "0"} KB)`);
|
|
86
|
+
if (result.conflictWarnings?.length) {
|
|
87
|
+
for (const w of result.conflictWarnings)
|
|
88
|
+
p.log.warn(` [WARN] ${w}`);
|
|
128
89
|
}
|
|
129
|
-
|
|
90
|
+
const warn = sizeWarning(result.sizeKB ?? 0);
|
|
91
|
+
if (warn)
|
|
92
|
+
p.log.warn(warn);
|
|
130
93
|
p.outro(`Next: ${chalk.cyan("arcana validate " + skillName)}`);
|
|
131
94
|
}
|
|
132
95
|
catch (err) {
|
|
133
|
-
|
|
96
|
+
spin.stop(`Failed to install ${skillName}`);
|
|
134
97
|
printErrorWithHint(err, true);
|
|
135
98
|
process.exit(1);
|
|
136
99
|
}
|
|
137
100
|
}
|
|
138
|
-
async function
|
|
101
|
+
async function installBatchInteractive(skillNames, provider, dryRun, force, noCheck) {
|
|
139
102
|
p.intro(chalk.bold(`Install ${skillNames.length} skills`));
|
|
140
103
|
for (const name of skillNames) {
|
|
141
104
|
try {
|
|
@@ -149,136 +112,112 @@ async function installMultipleInteractive(skillNames, provider, dryRun, force) {
|
|
|
149
112
|
if (dryRun) {
|
|
150
113
|
const wouldInstall = [];
|
|
151
114
|
const alreadyInstalled = [];
|
|
152
|
-
for (const
|
|
153
|
-
if (isSkillInstalled(
|
|
154
|
-
alreadyInstalled.push(
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
wouldInstall.push(skillName);
|
|
158
|
-
}
|
|
115
|
+
for (const name of skillNames) {
|
|
116
|
+
if (isSkillInstalled(name) && !force)
|
|
117
|
+
alreadyInstalled.push(name);
|
|
118
|
+
else
|
|
119
|
+
wouldInstall.push(name);
|
|
159
120
|
}
|
|
160
|
-
if (wouldInstall.length > 0)
|
|
121
|
+
if (wouldInstall.length > 0)
|
|
161
122
|
p.log.info(`Would install: ${wouldInstall.join(", ")}`);
|
|
162
|
-
|
|
163
|
-
if (alreadyInstalled.length > 0) {
|
|
123
|
+
if (alreadyInstalled.length > 0)
|
|
164
124
|
p.log.info(`Already installed: ${alreadyInstalled.join(", ")}`);
|
|
165
|
-
}
|
|
166
125
|
p.outro("Dry run complete.");
|
|
167
126
|
return;
|
|
168
127
|
}
|
|
169
128
|
const spin = p.spinner();
|
|
170
129
|
spin.start(`Processing ${skillNames.length} skills...`);
|
|
171
|
-
const
|
|
172
|
-
const
|
|
173
|
-
const
|
|
130
|
+
const installed = [];
|
|
131
|
+
const skipped = [];
|
|
132
|
+
const failed = [];
|
|
174
133
|
for (let i = 0; i < skillNames.length; i++) {
|
|
175
|
-
const
|
|
176
|
-
if (isSkillInstalled(
|
|
177
|
-
|
|
134
|
+
const name = skillNames[i];
|
|
135
|
+
if (isSkillInstalled(name) && !force) {
|
|
136
|
+
skipped.push(name);
|
|
178
137
|
continue;
|
|
179
138
|
}
|
|
180
|
-
spin.message(`Installing ${chalk.bold(
|
|
139
|
+
spin.message(`Installing ${chalk.bold(name)} (${i + 1}/${skillNames.length}) from ${provider.name}...`);
|
|
181
140
|
try {
|
|
182
|
-
const
|
|
183
|
-
if (
|
|
184
|
-
|
|
185
|
-
|
|
141
|
+
const result = await installOneCore(name, provider, { force, noCheck });
|
|
142
|
+
if (result.success) {
|
|
143
|
+
installed.push(name);
|
|
144
|
+
}
|
|
145
|
+
else {
|
|
146
|
+
failed.push(name);
|
|
186
147
|
}
|
|
187
|
-
installSkill(skillName, files);
|
|
188
|
-
const remote = await provider.info(skillName);
|
|
189
|
-
writeSkillMeta(skillName, {
|
|
190
|
-
version: remote?.version ?? "0.0.0",
|
|
191
|
-
installedAt: new Date().toISOString(),
|
|
192
|
-
source: provider.name,
|
|
193
|
-
description: remote?.description,
|
|
194
|
-
fileCount: files.length,
|
|
195
|
-
sizeBytes: files.reduce((s, f) => s + f.content.length, 0),
|
|
196
|
-
});
|
|
197
|
-
installedList.push(skillName);
|
|
198
148
|
}
|
|
199
149
|
catch (err) {
|
|
200
|
-
|
|
150
|
+
failed.push(name);
|
|
201
151
|
if (err instanceof Error)
|
|
202
|
-
p.log.warn(`Failed to install ${
|
|
152
|
+
p.log.warn(`Failed to install ${name}: ${err.message}`);
|
|
203
153
|
}
|
|
204
154
|
}
|
|
205
|
-
spin.stop(
|
|
206
|
-
p.log.info(`${
|
|
155
|
+
spin.stop("Done");
|
|
156
|
+
p.log.info(`${installed.length} installed${skipped.length > 0 ? `, ${skipped.length} skipped (already installed)` : ""}${failed.length > 0 ? `, ${failed.length} failed` : ""}`);
|
|
207
157
|
p.outro(`Next: ${chalk.cyan("arcana doctor")}`);
|
|
208
|
-
if (
|
|
158
|
+
if (failed.length > 0)
|
|
209
159
|
process.exit(1);
|
|
210
160
|
}
|
|
211
|
-
async function installAllInteractive(providers, dryRun, force) {
|
|
161
|
+
async function installAllInteractive(providers, dryRun, force, noCheck) {
|
|
212
162
|
p.intro(chalk.bold("Install all skills"));
|
|
213
163
|
const spin = p.spinner();
|
|
214
164
|
spin.start("Fetching skill list...");
|
|
215
165
|
if (dryRun) {
|
|
216
166
|
let total = 0;
|
|
217
|
-
for (const
|
|
167
|
+
for (const prov of providers) {
|
|
218
168
|
try {
|
|
219
|
-
const skills = await
|
|
169
|
+
const skills = await prov.list();
|
|
220
170
|
total += skills.length;
|
|
221
171
|
}
|
|
222
172
|
catch (err) {
|
|
223
173
|
if (err instanceof Error)
|
|
224
|
-
p.log.warn(`Failed to list ${
|
|
174
|
+
p.log.warn(`Failed to list ${prov.name}: ${err.message}`);
|
|
225
175
|
}
|
|
226
176
|
}
|
|
227
177
|
spin.stop(`Would install ${total} skills`);
|
|
228
178
|
p.outro("Dry run complete.");
|
|
229
179
|
return;
|
|
230
180
|
}
|
|
231
|
-
const
|
|
232
|
-
const
|
|
233
|
-
const
|
|
234
|
-
for (const
|
|
181
|
+
const installed = [];
|
|
182
|
+
const skipped = [];
|
|
183
|
+
const failed = [];
|
|
184
|
+
for (const prov of providers) {
|
|
235
185
|
let skills;
|
|
236
186
|
try {
|
|
237
|
-
skills = await
|
|
187
|
+
skills = await prov.list();
|
|
238
188
|
}
|
|
239
189
|
catch (err) {
|
|
240
190
|
if (err instanceof Error)
|
|
241
|
-
p.log.warn(`Failed to list ${
|
|
191
|
+
p.log.warn(`Failed to list ${prov.name}: ${err.message}`);
|
|
242
192
|
continue;
|
|
243
193
|
}
|
|
244
|
-
|
|
245
|
-
for (let i = 0; i < total; i++) {
|
|
194
|
+
for (let i = 0; i < skills.length; i++) {
|
|
246
195
|
const skill = skills[i];
|
|
247
196
|
if (isSkillInstalled(skill.name) && !force) {
|
|
248
|
-
|
|
197
|
+
skipped.push(skill.name);
|
|
249
198
|
continue;
|
|
250
199
|
}
|
|
200
|
+
spin.message(`Installing ${chalk.bold(skill.name)} (${i + 1}/${skills.length}) from ${prov.name}...`);
|
|
251
201
|
try {
|
|
252
|
-
|
|
253
|
-
|
|
254
|
-
|
|
255
|
-
|
|
256
|
-
|
|
257
|
-
}
|
|
258
|
-
installSkill(skill.name, files);
|
|
259
|
-
writeSkillMeta(skill.name, {
|
|
260
|
-
version: skill.version,
|
|
261
|
-
installedAt: new Date().toISOString(),
|
|
262
|
-
source: provider.name,
|
|
263
|
-
description: skill.description,
|
|
264
|
-
fileCount: files.length,
|
|
265
|
-
sizeBytes: files.reduce((s, f) => s + f.content.length, 0),
|
|
266
|
-
});
|
|
267
|
-
installedList.push(skill.name);
|
|
202
|
+
const result = await installOneCore(skill.name, prov, { force, noCheck });
|
|
203
|
+
if (result.success)
|
|
204
|
+
installed.push(skill.name);
|
|
205
|
+
else
|
|
206
|
+
failed.push(skill.name);
|
|
268
207
|
}
|
|
269
208
|
catch (err) {
|
|
270
|
-
|
|
209
|
+
failed.push(skill.name);
|
|
271
210
|
if (err instanceof Error)
|
|
272
211
|
p.log.warn(`Failed to install ${skill.name}: ${err.message}`);
|
|
273
212
|
}
|
|
274
213
|
}
|
|
275
214
|
}
|
|
276
|
-
spin.stop(`Installed ${
|
|
277
|
-
if (
|
|
278
|
-
p.log.info(`Skipped ${
|
|
215
|
+
spin.stop(`Installed ${installed.length} skills${failed.length > 0 ? `, ${failed.length} failed` : ""}`);
|
|
216
|
+
if (skipped.length > 0) {
|
|
217
|
+
p.log.info(`Skipped ${skipped.length} already installed${force ? "" : " (use --force to reinstall)"}`);
|
|
279
218
|
}
|
|
280
219
|
p.outro(`Next: ${chalk.cyan("arcana doctor")}`);
|
|
281
|
-
if (
|
|
220
|
+
if (failed.length > 0)
|
|
282
221
|
process.exit(1);
|
|
283
222
|
}
|
|
284
223
|
async function installJson(skillNames, opts) {
|
|
@@ -288,17 +227,21 @@ async function installJson(skillNames, opts) {
|
|
|
288
227
|
}
|
|
289
228
|
const providerName = opts.provider ?? loadConfig().defaultProvider;
|
|
290
229
|
const providers = opts.all ? getProviders() : [getProvider(providerName)];
|
|
230
|
+
const installed = [];
|
|
231
|
+
const skipped = [];
|
|
232
|
+
const failed = [];
|
|
233
|
+
const failedErrors = {};
|
|
291
234
|
if (opts.all) {
|
|
292
235
|
if (opts.dryRun) {
|
|
293
236
|
const wouldInstall = [];
|
|
294
237
|
const errors = [];
|
|
295
|
-
for (const
|
|
238
|
+
for (const prov of providers) {
|
|
296
239
|
try {
|
|
297
|
-
const skills = await
|
|
298
|
-
wouldInstall.push(...skills.map(s => s.name));
|
|
240
|
+
const skills = await prov.list();
|
|
241
|
+
wouldInstall.push(...skills.map((s) => s.name));
|
|
299
242
|
}
|
|
300
243
|
catch (err) {
|
|
301
|
-
errors.push(`Failed to list ${
|
|
244
|
+
errors.push(`Failed to list ${prov.name}: ${err instanceof Error ? err.message : "unknown error"}`);
|
|
302
245
|
}
|
|
303
246
|
}
|
|
304
247
|
const result = { dryRun: true, wouldInstall };
|
|
@@ -307,57 +250,42 @@ async function installJson(skillNames, opts) {
|
|
|
307
250
|
console.log(JSON.stringify(result));
|
|
308
251
|
return;
|
|
309
252
|
}
|
|
310
|
-
const installedList = [];
|
|
311
|
-
const skippedList = [];
|
|
312
|
-
const failedList = [];
|
|
313
|
-
const failedErrors = {};
|
|
314
253
|
const errors = [];
|
|
315
|
-
for (const
|
|
254
|
+
for (const prov of providers) {
|
|
316
255
|
let skills;
|
|
317
256
|
try {
|
|
318
|
-
skills = await
|
|
257
|
+
skills = await prov.list();
|
|
319
258
|
}
|
|
320
259
|
catch (err) {
|
|
321
|
-
errors.push(`Failed to list ${
|
|
260
|
+
errors.push(`Failed to list ${prov.name}: ${err instanceof Error ? err.message : "unknown error"}`);
|
|
322
261
|
continue;
|
|
323
262
|
}
|
|
324
263
|
for (const skill of skills) {
|
|
325
264
|
if (isSkillInstalled(skill.name) && !opts.force) {
|
|
326
|
-
|
|
265
|
+
skipped.push(skill.name);
|
|
327
266
|
continue;
|
|
328
267
|
}
|
|
329
268
|
try {
|
|
330
|
-
const
|
|
331
|
-
if (
|
|
332
|
-
|
|
333
|
-
|
|
334
|
-
|
|
269
|
+
const result = await installOneCore(skill.name, prov, { force: opts.force, noCheck: opts.noCheck });
|
|
270
|
+
if (result.success)
|
|
271
|
+
installed.push(skill.name);
|
|
272
|
+
else {
|
|
273
|
+
failed.push(skill.name);
|
|
274
|
+
failedErrors[skill.name] = result.error ?? "Install failed";
|
|
335
275
|
}
|
|
336
|
-
installSkill(skill.name, files);
|
|
337
|
-
writeSkillMeta(skill.name, {
|
|
338
|
-
version: skill.version,
|
|
339
|
-
installedAt: new Date().toISOString(),
|
|
340
|
-
source: provider.name,
|
|
341
|
-
description: skill.description,
|
|
342
|
-
fileCount: files.length,
|
|
343
|
-
sizeBytes: files.reduce((s, f) => s + f.content.length, 0),
|
|
344
|
-
});
|
|
345
|
-
installedList.push(skill.name);
|
|
346
276
|
}
|
|
347
277
|
catch (err) {
|
|
348
|
-
|
|
278
|
+
failed.push(skill.name);
|
|
349
279
|
failedErrors[skill.name] = err instanceof Error ? err.message : "unknown";
|
|
350
280
|
}
|
|
351
281
|
}
|
|
352
282
|
}
|
|
353
|
-
const result = { installed
|
|
283
|
+
const result = { installed, skipped, failed };
|
|
354
284
|
if (errors.length > 0)
|
|
355
285
|
result.errors = errors;
|
|
356
286
|
if (Object.keys(failedErrors).length > 0)
|
|
357
287
|
result.failedErrors = failedErrors;
|
|
358
288
|
console.log(JSON.stringify(result));
|
|
359
|
-
if (failedList.length > 0)
|
|
360
|
-
process.exit(1);
|
|
361
289
|
}
|
|
362
290
|
else {
|
|
363
291
|
const provider = providers[0];
|
|
@@ -365,40 +293,25 @@ async function installJson(skillNames, opts) {
|
|
|
365
293
|
console.log(JSON.stringify({ dryRun: true, wouldInstall: skillNames }));
|
|
366
294
|
return;
|
|
367
295
|
}
|
|
368
|
-
const
|
|
369
|
-
const skippedList = [];
|
|
370
|
-
const failedList = [];
|
|
371
|
-
for (const skillName of skillNames) {
|
|
296
|
+
for (const name of skillNames) {
|
|
372
297
|
try {
|
|
373
|
-
validateSlug(
|
|
374
|
-
if (isSkillInstalled(
|
|
375
|
-
|
|
376
|
-
continue;
|
|
377
|
-
}
|
|
378
|
-
const files = await provider.fetch(skillName);
|
|
379
|
-
if (!preInstallScan(skillName, files, opts.force)) {
|
|
380
|
-
failedList.push(skillName);
|
|
298
|
+
validateSlug(name, "skill name");
|
|
299
|
+
if (isSkillInstalled(name) && !opts.force) {
|
|
300
|
+
skipped.push(name);
|
|
381
301
|
continue;
|
|
382
302
|
}
|
|
383
|
-
|
|
384
|
-
|
|
385
|
-
|
|
386
|
-
|
|
387
|
-
|
|
388
|
-
source: provider.name,
|
|
389
|
-
description: remote?.description,
|
|
390
|
-
fileCount: files.length,
|
|
391
|
-
sizeBytes: files.reduce((s, f) => s + f.content.length, 0),
|
|
392
|
-
});
|
|
393
|
-
installedList.push(skillName);
|
|
303
|
+
const result = await installOneCore(name, provider, { force: opts.force, noCheck: opts.noCheck });
|
|
304
|
+
if (result.success)
|
|
305
|
+
installed.push(name);
|
|
306
|
+
else
|
|
307
|
+
failed.push(name);
|
|
394
308
|
}
|
|
395
|
-
catch
|
|
396
|
-
|
|
309
|
+
catch {
|
|
310
|
+
failed.push(name);
|
|
397
311
|
}
|
|
398
312
|
}
|
|
399
|
-
console.log(JSON.stringify({ installed
|
|
400
|
-
if (failedList.length > 0)
|
|
401
|
-
process.exit(1);
|
|
313
|
+
console.log(JSON.stringify({ installed, skipped, failed }));
|
|
402
314
|
}
|
|
315
|
+
if (failed.length > 0)
|
|
316
|
+
process.exit(1);
|
|
403
317
|
}
|
|
404
|
-
//# sourceMappingURL=install.js.map
|
package/dist/commands/list.d.ts
CHANGED
package/dist/commands/list.js
CHANGED
|
@@ -29,6 +29,8 @@ export async function listCommand(opts) {
|
|
|
29
29
|
description: skill.description,
|
|
30
30
|
source: skill.source,
|
|
31
31
|
installed: isSkillInstalled(skill.name),
|
|
32
|
+
verified: skill.verified,
|
|
33
|
+
tags: skill.tags,
|
|
32
34
|
});
|
|
33
35
|
}
|
|
34
36
|
}
|
|
@@ -44,9 +46,11 @@ export async function listCommand(opts) {
|
|
|
44
46
|
console.log(ui.bold(` ${skills.length} skills available:`));
|
|
45
47
|
console.log();
|
|
46
48
|
const rows = skills.map((skill) => [
|
|
47
|
-
ui.bold(skill.name),
|
|
49
|
+
ui.bold(skill.name) + (skill.verified ? " " + ui.success("[V]") : ""),
|
|
48
50
|
ui.dim(`v${skill.version}`),
|
|
49
|
-
skill.description.slice(0, DESC_TRUNCATE_LENGTH) +
|
|
51
|
+
skill.description.slice(0, DESC_TRUNCATE_LENGTH) +
|
|
52
|
+
(skill.description.length > DESC_TRUNCATE_LENGTH ? "..." : ""),
|
|
53
|
+
skill.tags?.slice(0, 3).join(", ") ?? "",
|
|
50
54
|
providers.length > 1 ? ui.dim(skill.source) : "",
|
|
51
55
|
skill.installed ? ui.success("[installed]") : "",
|
|
52
56
|
]);
|
|
@@ -72,7 +76,12 @@ function listInstalled(json) {
|
|
|
72
76
|
if (json) {
|
|
73
77
|
const skills = dirs.map((name) => {
|
|
74
78
|
const meta = readSkillMeta(name);
|
|
75
|
-
return {
|
|
79
|
+
return {
|
|
80
|
+
name,
|
|
81
|
+
version: meta?.version ?? "unknown",
|
|
82
|
+
source: meta?.source ?? "local",
|
|
83
|
+
installedAt: meta?.installedAt ?? null,
|
|
84
|
+
};
|
|
76
85
|
});
|
|
77
86
|
console.log(JSON.stringify({ skills }, null, 2));
|
|
78
87
|
return;
|
|
@@ -97,4 +106,3 @@ function listInstalled(json) {
|
|
|
97
106
|
table(rows);
|
|
98
107
|
console.log();
|
|
99
108
|
}
|
|
100
|
-
//# sourceMappingURL=list.js.map
|