@sporesec/arcana 2.4.0 → 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 +120 -9
- 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 +0 -1
- package/dist/commands/clean.js +19 -8
- package/dist/commands/compact.d.ts +2 -1
- package/dist/commands/compact.js +74 -14
- 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 +64 -23
- 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 +26 -33
- 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 +0 -1
- package/dist/commands/optimize.js +111 -20
- 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 +24 -20
- 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 +0 -1
- package/dist/utils/fs.js +30 -11
- 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 +74 -62
- 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/compact.d.ts.map +0 -1
- package/dist/commands/compact.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/optimize.d.ts.map +0 -1
- package/dist/commands/optimize.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/update.js
CHANGED
|
@@ -6,15 +6,29 @@ import { getProvider, getProviders } from "../registry.js";
|
|
|
6
6
|
import { ui, banner, spinner, noopSpinner } from "../utils/ui.js";
|
|
7
7
|
import { loadConfig } from "../utils/config.js";
|
|
8
8
|
import { validateSlug } from "../utils/validate.js";
|
|
9
|
+
import { updateLockEntry } from "../utils/integrity.js";
|
|
9
10
|
function isNewer(remoteVersion, localVersion) {
|
|
10
11
|
const local = semver.valid(semver.coerce(localVersion)) ?? "0.0.0";
|
|
11
12
|
const remote = semver.valid(semver.coerce(remoteVersion)) ?? "0.0.0";
|
|
12
13
|
return semver.gt(remote, local);
|
|
13
14
|
}
|
|
15
|
+
/** Fetch, write files, write meta, update lock for a single skill. */
|
|
16
|
+
async function applyUpdate(skillName, remote, provider) {
|
|
17
|
+
const files = await provider.fetch(skillName);
|
|
18
|
+
installSkill(skillName, files);
|
|
19
|
+
writeSkillMeta(skillName, {
|
|
20
|
+
version: remote.version,
|
|
21
|
+
installedAt: new Date().toISOString(),
|
|
22
|
+
source: provider.name,
|
|
23
|
+
description: remote.description,
|
|
24
|
+
fileCount: files.length,
|
|
25
|
+
});
|
|
26
|
+
updateLockEntry(skillName, remote.version, provider.name, files);
|
|
27
|
+
return files;
|
|
28
|
+
}
|
|
14
29
|
export async function updateCommand(skills, opts) {
|
|
15
|
-
if (!opts.json)
|
|
30
|
+
if (!opts.json)
|
|
16
31
|
banner();
|
|
17
|
-
}
|
|
18
32
|
if (skills.length === 0 && !opts.all) {
|
|
19
33
|
if (opts.json) {
|
|
20
34
|
console.log(JSON.stringify({ error: "Specify a skill name or use --all" }));
|
|
@@ -40,13 +54,13 @@ export async function updateCommand(skills, opts) {
|
|
|
40
54
|
}
|
|
41
55
|
const providerName = opts.provider ?? loadConfig().defaultProvider;
|
|
42
56
|
if (opts.all) {
|
|
43
|
-
await
|
|
57
|
+
await updateBatch(null, installDir, providerName, opts.json, opts.dryRun);
|
|
44
58
|
}
|
|
45
59
|
else if (skills.length === 1) {
|
|
46
60
|
await updateOne(skills[0], installDir, providerName, opts.json, opts.dryRun);
|
|
47
61
|
}
|
|
48
62
|
else {
|
|
49
|
-
await
|
|
63
|
+
await updateBatch(skills, installDir, providerName, opts.json, opts.dryRun);
|
|
50
64
|
}
|
|
51
65
|
}
|
|
52
66
|
async function updateOne(skillName, installDir, providerName, json, dryRun) {
|
|
@@ -55,7 +69,12 @@ async function updateOne(skillName, installDir, providerName, json, dryRun) {
|
|
|
55
69
|
}
|
|
56
70
|
catch (err) {
|
|
57
71
|
if (json) {
|
|
58
|
-
console.log(JSON.stringify({
|
|
72
|
+
console.log(JSON.stringify({
|
|
73
|
+
updated: [],
|
|
74
|
+
upToDate: [],
|
|
75
|
+
failed: [skillName],
|
|
76
|
+
error: err instanceof Error ? err.message : "Invalid name",
|
|
77
|
+
}));
|
|
59
78
|
}
|
|
60
79
|
else {
|
|
61
80
|
console.log(ui.error(` ${err instanceof Error ? err.message : "Invalid skill name"}`));
|
|
@@ -102,7 +121,10 @@ async function updateOne(skillName, installDir, providerName, json, dryRun) {
|
|
|
102
121
|
}
|
|
103
122
|
if (dryRun) {
|
|
104
123
|
if (json) {
|
|
105
|
-
console.log(JSON.stringify({
|
|
124
|
+
console.log(JSON.stringify({
|
|
125
|
+
dryRun: true,
|
|
126
|
+
wouldUpdate: [{ name: skillName, from: meta?.version ?? "unknown", to: remote.version }],
|
|
127
|
+
}));
|
|
106
128
|
}
|
|
107
129
|
else {
|
|
108
130
|
s.info(`${ui.bold(skillName)} would be updated: v${meta?.version ?? "unknown"} -> v${remote.version}`);
|
|
@@ -111,15 +133,7 @@ async function updateOne(skillName, installDir, providerName, json, dryRun) {
|
|
|
111
133
|
return;
|
|
112
134
|
}
|
|
113
135
|
s.text = `Updating ${ui.bold(skillName)}...`;
|
|
114
|
-
const files = await
|
|
115
|
-
installSkill(skillName, files);
|
|
116
|
-
writeSkillMeta(skillName, {
|
|
117
|
-
version: remote.version,
|
|
118
|
-
installedAt: new Date().toISOString(),
|
|
119
|
-
source: providerName,
|
|
120
|
-
description: remote.description,
|
|
121
|
-
fileCount: files.length,
|
|
122
|
-
});
|
|
136
|
+
const files = await applyUpdate(skillName, remote, provider);
|
|
123
137
|
if (json) {
|
|
124
138
|
console.log(JSON.stringify({ updated: [skillName], upToDate: [], failed: [] }));
|
|
125
139
|
}
|
|
@@ -130,7 +144,12 @@ async function updateOne(skillName, installDir, providerName, json, dryRun) {
|
|
|
130
144
|
}
|
|
131
145
|
catch (err) {
|
|
132
146
|
if (json) {
|
|
133
|
-
console.log(JSON.stringify({
|
|
147
|
+
console.log(JSON.stringify({
|
|
148
|
+
updated: [],
|
|
149
|
+
upToDate: [],
|
|
150
|
+
failed: [skillName],
|
|
151
|
+
error: err instanceof Error ? err.message : "Update failed",
|
|
152
|
+
}));
|
|
134
153
|
}
|
|
135
154
|
else {
|
|
136
155
|
s.fail(`Failed to update ${skillName}`);
|
|
@@ -141,102 +160,35 @@ async function updateOne(skillName, installDir, providerName, json, dryRun) {
|
|
|
141
160
|
process.exit(1);
|
|
142
161
|
}
|
|
143
162
|
}
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
163
|
+
/**
|
|
164
|
+
* Batch update. If `skillNames` is null, update all installed skills.
|
|
165
|
+
* If `skillNames` is provided, update only those specific skills.
|
|
166
|
+
*/
|
|
167
|
+
async function updateBatch(skillNames, installDir, providerName, json, dryRun) {
|
|
168
|
+
// Validate explicit skill names
|
|
169
|
+
if (skillNames) {
|
|
170
|
+
for (const name of skillNames) {
|
|
171
|
+
try {
|
|
172
|
+
validateSlug(name, "skill name");
|
|
152
173
|
}
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
const failedList = [];
|
|
166
|
-
const dryRunUpdates = [];
|
|
167
|
-
for (let i = 0; i < skillNames.length; i++) {
|
|
168
|
-
const skillName = skillNames[i];
|
|
169
|
-
const skillDir = join(installDir, skillName);
|
|
170
|
-
if (!existsSync(skillDir)) {
|
|
171
|
-
failedList.push(skillName);
|
|
172
|
-
if (!json)
|
|
173
|
-
console.error(ui.dim(` ${skillName} is not installed`));
|
|
174
|
-
continue;
|
|
175
|
-
}
|
|
176
|
-
try {
|
|
177
|
-
const remote = await provider.info(skillName);
|
|
178
|
-
if (!remote) {
|
|
179
|
-
failedList.push(skillName);
|
|
180
|
-
continue;
|
|
181
|
-
}
|
|
182
|
-
const meta = readSkillMeta(skillName);
|
|
183
|
-
if (!isNewer(remote.version, meta?.version)) {
|
|
184
|
-
upToDateList.push(skillName);
|
|
185
|
-
continue;
|
|
186
|
-
}
|
|
187
|
-
if (dryRun) {
|
|
188
|
-
dryRunUpdates.push({ name: skillName, from: meta?.version ?? "unknown", to: remote.version });
|
|
189
|
-
continue;
|
|
190
|
-
}
|
|
191
|
-
s.text = `Updating ${ui.bold(skillName)} (${i + 1}/${skillNames.length})...`;
|
|
192
|
-
const files = await provider.fetch(skillName);
|
|
193
|
-
installSkill(skillName, files);
|
|
194
|
-
writeSkillMeta(skillName, {
|
|
195
|
-
version: remote.version,
|
|
196
|
-
installedAt: new Date().toISOString(),
|
|
197
|
-
source: providerName,
|
|
198
|
-
description: remote.description,
|
|
199
|
-
fileCount: files.length,
|
|
200
|
-
});
|
|
201
|
-
updatedList.push(skillName);
|
|
202
|
-
}
|
|
203
|
-
catch (err) {
|
|
204
|
-
failedList.push(skillName);
|
|
205
|
-
if (err instanceof Error && !json)
|
|
206
|
-
console.error(ui.dim(` Failed to update ${skillName}: ${err.message}`));
|
|
207
|
-
}
|
|
208
|
-
}
|
|
209
|
-
if (dryRun) {
|
|
210
|
-
if (json) {
|
|
211
|
-
console.log(JSON.stringify({ dryRun: true, wouldUpdate: dryRunUpdates, upToDate: upToDateList, failed: failedList }));
|
|
212
|
-
}
|
|
213
|
-
else {
|
|
214
|
-
s.stop();
|
|
215
|
-
if (dryRunUpdates.length === 0) {
|
|
216
|
-
console.log(ui.dim(" All skills are up to date."));
|
|
217
|
-
}
|
|
218
|
-
else {
|
|
219
|
-
for (const u of dryRunUpdates) {
|
|
220
|
-
console.log(` ${ui.bold(u.name)}: v${u.from} -> v${u.to}`);
|
|
174
|
+
catch (err) {
|
|
175
|
+
if (json) {
|
|
176
|
+
console.log(JSON.stringify({
|
|
177
|
+
updated: [],
|
|
178
|
+
upToDate: [],
|
|
179
|
+
failed: skillNames,
|
|
180
|
+
error: err instanceof Error ? err.message : "Invalid name",
|
|
181
|
+
}));
|
|
182
|
+
}
|
|
183
|
+
else {
|
|
184
|
+
console.log(ui.error(` ${err instanceof Error ? err.message : "Invalid skill name"}`));
|
|
185
|
+
console.log();
|
|
221
186
|
}
|
|
187
|
+
process.exit(1);
|
|
222
188
|
}
|
|
223
|
-
console.log();
|
|
224
189
|
}
|
|
225
|
-
return;
|
|
226
|
-
}
|
|
227
|
-
if (json) {
|
|
228
|
-
console.log(JSON.stringify({ updated: updatedList, upToDate: upToDateList, failed: failedList }));
|
|
229
190
|
}
|
|
230
|
-
|
|
231
|
-
s.succeed(`Update complete`);
|
|
232
|
-
console.log(ui.dim(` ${updatedList.length} updated, ${upToDateList.length} up to date${failedList.length > 0 ? `, ${failedList.length} failed` : ""}`));
|
|
233
|
-
console.log();
|
|
234
|
-
}
|
|
235
|
-
if (failedList.length > 0)
|
|
236
|
-
process.exit(1);
|
|
237
|
-
}
|
|
238
|
-
async function updateAll(installDir, providerName, json, dryRun) {
|
|
239
|
-
const installed = readdirSync(installDir).filter((d) => statSync(join(installDir, d)).isDirectory());
|
|
191
|
+
const installed = skillNames ?? readdirSync(installDir).filter((d) => statSync(join(installDir, d)).isDirectory());
|
|
240
192
|
if (installed.length === 0) {
|
|
241
193
|
if (json) {
|
|
242
194
|
console.log(JSON.stringify({ updated: [], upToDate: [], failed: [] }));
|
|
@@ -254,69 +206,106 @@ async function updateAll(installDir, providerName, json, dryRun) {
|
|
|
254
206
|
const failedList = [];
|
|
255
207
|
const skippedList = [];
|
|
256
208
|
const dryRunUpdates = [];
|
|
257
|
-
|
|
258
|
-
//
|
|
209
|
+
// For --all mode, use all providers and pre-fetch skill lists (avoids N+1 info() calls)
|
|
210
|
+
// For explicit names, use single provider with per-skill info() calls
|
|
211
|
+
const isAllMode = skillNames === null;
|
|
212
|
+
const providers = isAllMode ? getProviders(providerName === "arcana" ? undefined : providerName) : [];
|
|
213
|
+
const singleProvider = isAllMode ? null : getProvider(providerName);
|
|
214
|
+
// Pre-fetch provider skill maps for --all mode
|
|
259
215
|
const providerSkillMaps = new Map();
|
|
260
|
-
|
|
261
|
-
|
|
262
|
-
|
|
263
|
-
|
|
264
|
-
|
|
265
|
-
|
|
216
|
+
if (isAllMode) {
|
|
217
|
+
for (const provider of providers) {
|
|
218
|
+
try {
|
|
219
|
+
const skills = await provider.list();
|
|
220
|
+
const map = new Map();
|
|
221
|
+
for (const skill of skills) {
|
|
222
|
+
map.set(skill.name, { version: skill.version, description: skill.description });
|
|
223
|
+
}
|
|
224
|
+
providerSkillMaps.set(provider.name, map);
|
|
225
|
+
}
|
|
226
|
+
catch (err) {
|
|
227
|
+
if (err instanceof Error && !json)
|
|
228
|
+
console.error(ui.dim(` Failed to list ${provider.name}: ${err.message}`));
|
|
266
229
|
}
|
|
267
|
-
providerSkillMaps.set(provider.name, map);
|
|
268
|
-
}
|
|
269
|
-
catch (err) {
|
|
270
|
-
if (err instanceof Error && !json)
|
|
271
|
-
console.error(ui.dim(` Failed to list ${provider.name}: ${err.message}`));
|
|
272
230
|
}
|
|
273
231
|
}
|
|
274
232
|
const total = installed.length;
|
|
275
233
|
for (let i = 0; i < total; i++) {
|
|
276
|
-
const
|
|
277
|
-
|
|
234
|
+
const name = installed[i];
|
|
235
|
+
// Check installation exists (for explicit names)
|
|
236
|
+
if (!isAllMode) {
|
|
237
|
+
const skillDir = join(installDir, name);
|
|
238
|
+
if (!existsSync(skillDir)) {
|
|
239
|
+
failedList.push(name);
|
|
240
|
+
if (!json)
|
|
241
|
+
console.error(ui.dim(` ${name} is not installed`));
|
|
242
|
+
continue;
|
|
243
|
+
}
|
|
244
|
+
}
|
|
278
245
|
try {
|
|
279
|
-
|
|
280
|
-
|
|
281
|
-
|
|
282
|
-
|
|
246
|
+
if (isAllMode) {
|
|
247
|
+
// Find across all providers
|
|
248
|
+
let found = false;
|
|
249
|
+
for (const provider of providers) {
|
|
250
|
+
const skillMap = providerSkillMaps.get(provider.name);
|
|
251
|
+
const remote = skillMap?.get(name) ?? null;
|
|
252
|
+
if (!remote)
|
|
253
|
+
continue;
|
|
254
|
+
found = true;
|
|
255
|
+
const meta = readSkillMeta(name);
|
|
256
|
+
if (!isNewer(remote.version, meta?.version)) {
|
|
257
|
+
upToDateList.push(name);
|
|
258
|
+
break;
|
|
259
|
+
}
|
|
260
|
+
if (dryRun) {
|
|
261
|
+
dryRunUpdates.push({ name, from: meta?.version ?? "unknown", to: remote.version });
|
|
262
|
+
break;
|
|
263
|
+
}
|
|
264
|
+
s.text = `Updating ${ui.bold(name)} (${i + 1}/${total})...`;
|
|
265
|
+
await applyUpdate(name, remote, provider);
|
|
266
|
+
updatedList.push(name);
|
|
267
|
+
break;
|
|
268
|
+
}
|
|
269
|
+
if (!found)
|
|
270
|
+
skippedList.push(name);
|
|
271
|
+
}
|
|
272
|
+
else {
|
|
273
|
+
// Single provider mode
|
|
274
|
+
const remote = await singleProvider.info(name);
|
|
275
|
+
if (!remote) {
|
|
276
|
+
failedList.push(name);
|
|
283
277
|
continue;
|
|
284
|
-
|
|
285
|
-
const meta = readSkillMeta(
|
|
278
|
+
}
|
|
279
|
+
const meta = readSkillMeta(name);
|
|
286
280
|
if (!isNewer(remote.version, meta?.version)) {
|
|
287
|
-
upToDateList.push(
|
|
288
|
-
|
|
281
|
+
upToDateList.push(name);
|
|
282
|
+
continue;
|
|
289
283
|
}
|
|
290
284
|
if (dryRun) {
|
|
291
|
-
dryRunUpdates.push({ name
|
|
292
|
-
|
|
285
|
+
dryRunUpdates.push({ name, from: meta?.version ?? "unknown", to: remote.version });
|
|
286
|
+
continue;
|
|
293
287
|
}
|
|
294
|
-
s.text = `Updating ${ui.bold(
|
|
295
|
-
|
|
296
|
-
|
|
297
|
-
writeSkillMeta(skillName, {
|
|
298
|
-
version: remote.version,
|
|
299
|
-
installedAt: new Date().toISOString(),
|
|
300
|
-
source: provider.name,
|
|
301
|
-
description: remote.description,
|
|
302
|
-
fileCount: files.length,
|
|
303
|
-
});
|
|
304
|
-
updatedList.push(skillName);
|
|
305
|
-
break;
|
|
288
|
+
s.text = `Updating ${ui.bold(name)} (${i + 1}/${total})...`;
|
|
289
|
+
await applyUpdate(name, remote, singleProvider);
|
|
290
|
+
updatedList.push(name);
|
|
306
291
|
}
|
|
307
292
|
}
|
|
308
293
|
catch (err) {
|
|
309
|
-
failedList.push(
|
|
294
|
+
failedList.push(name);
|
|
310
295
|
if (err instanceof Error && !json)
|
|
311
|
-
console.error(ui.dim(` Failed to update ${
|
|
312
|
-
continue;
|
|
296
|
+
console.error(ui.dim(` Failed to update ${name}: ${err.message}`));
|
|
313
297
|
}
|
|
314
|
-
if (!found)
|
|
315
|
-
skippedList.push(skillName);
|
|
316
298
|
}
|
|
299
|
+
// Output results
|
|
317
300
|
if (dryRun) {
|
|
318
301
|
if (json) {
|
|
319
|
-
console.log(JSON.stringify({
|
|
302
|
+
console.log(JSON.stringify({
|
|
303
|
+
dryRun: true,
|
|
304
|
+
wouldUpdate: dryRunUpdates,
|
|
305
|
+
upToDate: upToDateList,
|
|
306
|
+
...(isAllMode ? { skipped: skippedList } : {}),
|
|
307
|
+
failed: failedList,
|
|
308
|
+
}));
|
|
320
309
|
}
|
|
321
310
|
else {
|
|
322
311
|
s.stop();
|
|
@@ -324,8 +313,10 @@ async function updateAll(installDir, providerName, json, dryRun) {
|
|
|
324
313
|
console.log(ui.dim(" All skills are up to date."));
|
|
325
314
|
}
|
|
326
315
|
else {
|
|
327
|
-
|
|
328
|
-
|
|
316
|
+
if (isAllMode) {
|
|
317
|
+
console.log(ui.bold(` ${dryRunUpdates.length} of ${total} skills have updates available:`));
|
|
318
|
+
console.log();
|
|
319
|
+
}
|
|
329
320
|
for (const u of dryRunUpdates) {
|
|
330
321
|
console.log(` ${ui.bold(u.name)}: v${u.from} -> v${u.to}`);
|
|
331
322
|
}
|
|
@@ -335,14 +326,23 @@ async function updateAll(installDir, providerName, json, dryRun) {
|
|
|
335
326
|
return;
|
|
336
327
|
}
|
|
337
328
|
if (json) {
|
|
338
|
-
console.log(JSON.stringify({
|
|
329
|
+
console.log(JSON.stringify({
|
|
330
|
+
updated: updatedList,
|
|
331
|
+
upToDate: upToDateList,
|
|
332
|
+
...(isAllMode ? { skipped: skippedList } : {}),
|
|
333
|
+
failed: failedList,
|
|
334
|
+
}));
|
|
339
335
|
}
|
|
340
336
|
else {
|
|
341
337
|
s.succeed(`Update complete`);
|
|
342
|
-
|
|
338
|
+
const parts = [`${updatedList.length} updated`, `${upToDateList.length} up to date`];
|
|
339
|
+
if (skippedList.length > 0)
|
|
340
|
+
parts.push(`${skippedList.length} skipped (not on provider)`);
|
|
341
|
+
if (failedList.length > 0)
|
|
342
|
+
parts.push(`${failedList.length} failed`);
|
|
343
|
+
console.log(ui.dim(` ${parts.join(", ")}`));
|
|
343
344
|
console.log();
|
|
344
345
|
}
|
|
345
346
|
if (failedList.length > 0)
|
|
346
347
|
process.exit(1);
|
|
347
348
|
}
|
|
348
|
-
//# sourceMappingURL=update.js.map
|
|
@@ -81,12 +81,23 @@ export async function validateCommand(skill, opts) {
|
|
|
81
81
|
}
|
|
82
82
|
}
|
|
83
83
|
}
|
|
84
|
-
catch {
|
|
84
|
+
catch {
|
|
85
|
+
/* skip if unreadable */
|
|
86
|
+
}
|
|
85
87
|
}
|
|
86
88
|
results.push(result);
|
|
87
89
|
}
|
|
88
90
|
if (opts.json) {
|
|
89
|
-
console.log(JSON.stringify({
|
|
91
|
+
console.log(JSON.stringify({
|
|
92
|
+
results: results.map((r) => ({
|
|
93
|
+
skill: r.skill,
|
|
94
|
+
valid: r.valid,
|
|
95
|
+
errors: r.errors,
|
|
96
|
+
warnings: r.warnings,
|
|
97
|
+
infos: r.infos,
|
|
98
|
+
fixed: r.fixed ?? false,
|
|
99
|
+
})),
|
|
100
|
+
}, null, 2));
|
|
90
101
|
if (results.some((r) => !r.valid))
|
|
91
102
|
process.exit(1);
|
|
92
103
|
return;
|
|
@@ -96,9 +107,7 @@ export async function validateCommand(skill, opts) {
|
|
|
96
107
|
let failed = 0;
|
|
97
108
|
let fixed = 0;
|
|
98
109
|
for (const r of results) {
|
|
99
|
-
const icon = r.valid
|
|
100
|
-
? r.warnings.length > 0 ? ui.warn("[!!]") : ui.success("[OK]")
|
|
101
|
-
: ui.error("[XX]");
|
|
110
|
+
const icon = r.valid ? (r.warnings.length > 0 ? ui.warn("[!!]") : ui.success("[OK]")) : ui.error("[XX]");
|
|
102
111
|
const fixTag = r.fixed ? ui.cyan(" [fixed]") : "";
|
|
103
112
|
console.log(` ${icon} ${ui.bold(r.skill)}${fixTag}`);
|
|
104
113
|
for (const err of r.errors) {
|
|
@@ -137,4 +146,3 @@ export async function validateCommand(skill, opts) {
|
|
|
137
146
|
if (failed > 0)
|
|
138
147
|
process.exit(1);
|
|
139
148
|
}
|
|
140
|
-
//# sourceMappingURL=validate.js.map
|
|
@@ -0,0 +1,116 @@
|
|
|
1
|
+
import { readdirSync, statSync } from "node:fs";
|
|
2
|
+
import { join } from "node:path";
|
|
3
|
+
import * as p from "@clack/prompts";
|
|
4
|
+
import chalk from "chalk";
|
|
5
|
+
import { getInstallDir, isSkillInstalled } from "../utils/fs.js";
|
|
6
|
+
import { verifySkillIntegrity } from "../utils/integrity.js";
|
|
7
|
+
import { validateSlug } from "../utils/validate.js";
|
|
8
|
+
import { renderBanner } from "../utils/help.js";
|
|
9
|
+
export async function verifyCommand(skillNames, opts) {
|
|
10
|
+
if (opts.json) {
|
|
11
|
+
return verifyJson(skillNames, opts);
|
|
12
|
+
}
|
|
13
|
+
console.log(renderBanner());
|
|
14
|
+
console.log();
|
|
15
|
+
const installDir = getInstallDir();
|
|
16
|
+
if (skillNames.length === 0 && !opts.all) {
|
|
17
|
+
p.intro(chalk.bold("Verify skill integrity"));
|
|
18
|
+
p.cancel("Specify a skill name or use --all");
|
|
19
|
+
p.log.info("Usage: arcana verify <skill-name> [skill2 ...]");
|
|
20
|
+
p.log.info(" arcana verify --all");
|
|
21
|
+
process.exit(1);
|
|
22
|
+
}
|
|
23
|
+
let skills;
|
|
24
|
+
if (opts.all) {
|
|
25
|
+
try {
|
|
26
|
+
skills = readdirSync(installDir).filter((d) => statSync(join(installDir, d)).isDirectory());
|
|
27
|
+
}
|
|
28
|
+
catch {
|
|
29
|
+
skills = [];
|
|
30
|
+
}
|
|
31
|
+
if (skills.length === 0) {
|
|
32
|
+
p.intro(chalk.bold("Verify skill integrity"));
|
|
33
|
+
p.log.info("No installed skills found.");
|
|
34
|
+
p.outro("Nothing to verify.");
|
|
35
|
+
return;
|
|
36
|
+
}
|
|
37
|
+
}
|
|
38
|
+
else {
|
|
39
|
+
for (const name of skillNames) {
|
|
40
|
+
try {
|
|
41
|
+
validateSlug(name, "skill name");
|
|
42
|
+
}
|
|
43
|
+
catch (err) {
|
|
44
|
+
p.log.error(err instanceof Error ? err.message : `Invalid skill name: ${name}`);
|
|
45
|
+
process.exit(1);
|
|
46
|
+
}
|
|
47
|
+
}
|
|
48
|
+
for (const name of skillNames) {
|
|
49
|
+
if (!isSkillInstalled(name)) {
|
|
50
|
+
p.log.error(`Skill ${chalk.bold(name)} is not installed.`);
|
|
51
|
+
process.exit(1);
|
|
52
|
+
}
|
|
53
|
+
}
|
|
54
|
+
skills = skillNames;
|
|
55
|
+
}
|
|
56
|
+
p.intro(chalk.bold("Verify skill integrity"));
|
|
57
|
+
const results = [];
|
|
58
|
+
for (const skill of skills) {
|
|
59
|
+
const status = verifySkillIntegrity(skill, installDir);
|
|
60
|
+
results.push({ skill, status });
|
|
61
|
+
if (status === "ok") {
|
|
62
|
+
p.log.info(`${chalk.green("[OK]")} ${skill}`);
|
|
63
|
+
}
|
|
64
|
+
else if (status === "modified") {
|
|
65
|
+
p.log.warn(`${chalk.yellow("[MODIFIED]")} ${skill}`);
|
|
66
|
+
}
|
|
67
|
+
else {
|
|
68
|
+
p.log.info(`${chalk.dim("[MISSING]")} ${skill}`);
|
|
69
|
+
}
|
|
70
|
+
}
|
|
71
|
+
const total = results.length;
|
|
72
|
+
const okCount = results.filter((r) => r.status === "ok").length;
|
|
73
|
+
const modifiedCount = results.filter((r) => r.status === "modified").length;
|
|
74
|
+
const missingCount = results.filter((r) => r.status === "missing").length;
|
|
75
|
+
console.log();
|
|
76
|
+
p.outro(`${total} skills verified, ${okCount} OK, ${modifiedCount} modified, ${missingCount} not tracked`);
|
|
77
|
+
if (modifiedCount > 0) {
|
|
78
|
+
process.exit(1);
|
|
79
|
+
}
|
|
80
|
+
}
|
|
81
|
+
async function verifyJson(skillNames, opts) {
|
|
82
|
+
const installDir = getInstallDir();
|
|
83
|
+
let skills;
|
|
84
|
+
if (opts.all) {
|
|
85
|
+
try {
|
|
86
|
+
skills = readdirSync(installDir).filter((d) => statSync(join(installDir, d)).isDirectory());
|
|
87
|
+
}
|
|
88
|
+
catch {
|
|
89
|
+
skills = [];
|
|
90
|
+
}
|
|
91
|
+
}
|
|
92
|
+
else if (skillNames.length === 0) {
|
|
93
|
+
console.log(JSON.stringify({ error: "Specify a skill name or use --all" }));
|
|
94
|
+
process.exit(1);
|
|
95
|
+
return;
|
|
96
|
+
}
|
|
97
|
+
else {
|
|
98
|
+
skills = skillNames;
|
|
99
|
+
}
|
|
100
|
+
const results = [];
|
|
101
|
+
for (const skill of skills) {
|
|
102
|
+
const status = verifySkillIntegrity(skill, installDir);
|
|
103
|
+
results.push({ skill, status });
|
|
104
|
+
}
|
|
105
|
+
const total = results.length;
|
|
106
|
+
const ok = results.filter((r) => r.status === "ok").length;
|
|
107
|
+
const modified = results.filter((r) => r.status === "modified").length;
|
|
108
|
+
const missing = results.filter((r) => r.status === "missing").length;
|
|
109
|
+
console.log(JSON.stringify({
|
|
110
|
+
results: results.map((r) => ({ skill: r.skill, status: r.status })),
|
|
111
|
+
summary: { total, ok, modified, missing },
|
|
112
|
+
}));
|
|
113
|
+
if (modified > 0) {
|
|
114
|
+
process.exit(1);
|
|
115
|
+
}
|
|
116
|
+
}
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
export declare const AGENT_LOG_MAX_AGE_DAYS = 7;
|
|
2
|
+
export declare const MAIN_LOG_MAX_AGE_DAYS = 30;
|
|
3
|
+
export declare const STALE_PROJECT_DAYS = 90;
|
|
4
|
+
export declare const PRUNE_DEFAULT_DAYS = 14;
|
|
5
|
+
export declare const PRUNE_SIZE_THRESHOLD_BYTES: number;
|
|
6
|
+
export declare const PRUNE_KEEP_NEWEST = 3;
|
|
7
|
+
export declare const LARGE_SKILL_KB_THRESHOLD = 50;
|
|
8
|
+
export declare const TOKENS_PER_KB = 256;
|
|
9
|
+
export declare const CONTEXT_WINDOW_TOKENS = 200000;
|
|
10
|
+
export declare const DESCRIPTION_TRUNCATION = 50;
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
// Retention & pruning
|
|
2
|
+
export const AGENT_LOG_MAX_AGE_DAYS = 7;
|
|
3
|
+
export const MAIN_LOG_MAX_AGE_DAYS = 30;
|
|
4
|
+
export const STALE_PROJECT_DAYS = 90;
|
|
5
|
+
export const PRUNE_DEFAULT_DAYS = 14;
|
|
6
|
+
export const PRUNE_SIZE_THRESHOLD_BYTES = 10 * 1024 * 1024; // 10 MB
|
|
7
|
+
export const PRUNE_KEEP_NEWEST = 3;
|
|
8
|
+
// Skill size warnings
|
|
9
|
+
export const LARGE_SKILL_KB_THRESHOLD = 50;
|
|
10
|
+
export const TOKENS_PER_KB = 256;
|
|
11
|
+
export const CONTEXT_WINDOW_TOKENS = 200_000;
|
|
12
|
+
// Display
|
|
13
|
+
export const DESCRIPTION_TRUNCATION = 50;
|
package/dist/index.d.ts
CHANGED
package/dist/index.js
CHANGED