skillbox 0.3.3 → 0.3.4
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.js +1 -1
- package/dist/commands/add-repo.js +43 -39
- package/dist/commands/add.js +16 -18
- package/dist/commands/list.js +11 -2
- package/dist/commands/update.js +40 -38
- package/dist/lib/output.js +42 -0
- package/package.json +7 -2
package/dist/cli.js
CHANGED
|
@@ -12,7 +12,7 @@ import { registerRemove } from "./commands/remove.js";
|
|
|
12
12
|
import { registerStatus } from "./commands/status.js";
|
|
13
13
|
import { registerUpdate } from "./commands/update.js";
|
|
14
14
|
const program = new Command();
|
|
15
|
-
program.name("skillbox").description("Local-first, agent-agnostic skills manager").version("0.3.
|
|
15
|
+
program.name("skillbox").description("Local-first, agent-agnostic skills manager").version("0.3.4");
|
|
16
16
|
registerAdd(program);
|
|
17
17
|
registerAgent(program);
|
|
18
18
|
registerConfig(program);
|
|
@@ -4,7 +4,7 @@ import { loadConfig } from "../lib/config.js";
|
|
|
4
4
|
import { parseRepoRef } from "../lib/github.js";
|
|
5
5
|
import { loadIndex, saveIndex, sortIndex, upsertSkill } from "../lib/index.js";
|
|
6
6
|
import { recordInstallPaths } from "../lib/installs.js";
|
|
7
|
-
import { printInfo, printJson } from "../lib/output.js";
|
|
7
|
+
import { printFailure, printInfo, printJson, printSkipped, printSuccess, startSpinner, stopSpinner, } from "../lib/output.js";
|
|
8
8
|
import { buildProjectAgentPaths } from "../lib/project-paths.js";
|
|
9
9
|
import { fetchRepoFile, listRepoSkills, normalizeRepoRef, writeRepoSkillDirectory, } from "../lib/repo-skills.js";
|
|
10
10
|
import { ensureProjectRegistered, resolveRuntime } from "../lib/runtime.js";
|
|
@@ -84,16 +84,27 @@ export async function handleRepoInstall(input, options) {
|
|
|
84
84
|
}
|
|
85
85
|
const summary = { installed: [], updated: [], skipped: [], failed: [] };
|
|
86
86
|
const index = await loadIndex();
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
87
|
+
const showProgress = !options.json;
|
|
88
|
+
const selectedSkills = skills.filter((s) => selected.includes(s.name));
|
|
89
|
+
const total = selectedSkills.length;
|
|
90
|
+
if (showProgress && total > 0) {
|
|
91
|
+
printInfo(`Adding ${total} skill${total === 1 ? "" : "s"} from ${ref.owner}/${ref.repo}...\n`);
|
|
92
|
+
}
|
|
93
|
+
for (let i = 0; i < selectedSkills.length; i++) {
|
|
94
|
+
const skill = selectedSkills[i];
|
|
95
|
+
const progress = `(${i + 1}/${total})`;
|
|
91
96
|
const alreadyInstalled = index.skills.some((entry) => entry.name === skill.name);
|
|
97
|
+
if (showProgress) {
|
|
98
|
+
startSpinner(`${skill.name} ${progress}`);
|
|
99
|
+
}
|
|
92
100
|
try {
|
|
93
101
|
const skillMarkdown = await fetchRepoFile(ref, ref.path ? `${ref.path}/${skill.skillFile}` : skill.skillFile);
|
|
94
102
|
const parsed = parseSkillMarkdown(skillMarkdown);
|
|
95
103
|
if (!parsed.description) {
|
|
96
104
|
summary.skipped.push(skill.name);
|
|
105
|
+
if (showProgress) {
|
|
106
|
+
printSkipped(skill.name, "missing description");
|
|
107
|
+
}
|
|
97
108
|
continue;
|
|
98
109
|
}
|
|
99
110
|
await writeRepoSkillDirectory(ref, skill.path, skill.name);
|
|
@@ -124,56 +135,49 @@ export async function handleRepoInstall(input, options) {
|
|
|
124
135
|
index.skills = nextIndex.skills;
|
|
125
136
|
if (alreadyInstalled) {
|
|
126
137
|
summary.updated.push(skill.name);
|
|
138
|
+
if (showProgress) {
|
|
139
|
+
printSuccess(skill.name, "updated");
|
|
140
|
+
}
|
|
127
141
|
}
|
|
128
142
|
else {
|
|
129
143
|
summary.installed.push(skill.name);
|
|
144
|
+
if (showProgress) {
|
|
145
|
+
printSuccess(skill.name);
|
|
146
|
+
}
|
|
130
147
|
}
|
|
131
148
|
}
|
|
132
149
|
catch (error) {
|
|
133
150
|
const message = getErrorMessage(error, "unknown");
|
|
134
151
|
summary.failed.push({ name: skill.name, reason: message });
|
|
152
|
+
if (showProgress) {
|
|
153
|
+
printFailure(skill.name, message);
|
|
154
|
+
}
|
|
135
155
|
}
|
|
136
156
|
}
|
|
157
|
+
if (showProgress) {
|
|
158
|
+
stopSpinner();
|
|
159
|
+
}
|
|
137
160
|
await saveIndex(sortIndex(index));
|
|
138
161
|
if (options.json) {
|
|
139
162
|
printJson({ ok: true, command: "add", data: { repo: `${ref.owner}/${ref.repo}`, ...summary } });
|
|
140
163
|
return;
|
|
141
164
|
}
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
if (
|
|
147
|
-
printInfo("");
|
|
148
|
-
printInfo(`Installed (${summary.installed.length}):`);
|
|
149
|
-
for (const name of summary.installed) {
|
|
150
|
-
printInfo(` ✓ ${name}`);
|
|
151
|
-
}
|
|
165
|
+
// Summary line
|
|
166
|
+
const added = summary.installed.length + summary.updated.length;
|
|
167
|
+
const failed = summary.failed.length;
|
|
168
|
+
const skipped = summary.skipped.length;
|
|
169
|
+
if (added > 0 && failed === 0 && skipped === 0) {
|
|
170
|
+
printInfo(`\nAdded ${added} skill${added === 1 ? "" : "s"} from ${ref.owner}/${ref.repo}.`);
|
|
152
171
|
}
|
|
153
|
-
if (
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
if (summary.skipped.length > 0) {
|
|
161
|
-
printInfo("");
|
|
162
|
-
printInfo(`Skipped (${summary.skipped.length}):`);
|
|
163
|
-
for (const name of summary.skipped) {
|
|
164
|
-
printInfo(` - ${name} (missing description)`);
|
|
165
|
-
}
|
|
172
|
+
else if (added > 0) {
|
|
173
|
+
const parts = [];
|
|
174
|
+
if (failed > 0)
|
|
175
|
+
parts.push(`${failed} failed`);
|
|
176
|
+
if (skipped > 0)
|
|
177
|
+
parts.push(`${skipped} skipped`);
|
|
178
|
+
printInfo(`\nAdded ${added} skill${added === 1 ? "" : "s"} (${parts.join(", ")}).`);
|
|
166
179
|
}
|
|
167
|
-
|
|
168
|
-
printInfo("");
|
|
169
|
-
printInfo(`Failed (${summary.failed.length}):`);
|
|
170
|
-
for (const failure of summary.failed) {
|
|
171
|
-
printInfo(` ✗ ${failure.name} (${failure.reason})`);
|
|
172
|
-
}
|
|
173
|
-
}
|
|
174
|
-
const total = summary.installed.length + summary.updated.length;
|
|
175
|
-
if (total === 0) {
|
|
176
|
-
printInfo("");
|
|
177
|
-
printInfo("No skills were added.");
|
|
180
|
+
else {
|
|
181
|
+
printInfo("\nNo skills were added.");
|
|
178
182
|
}
|
|
179
183
|
}
|
package/dist/commands/add.js
CHANGED
|
@@ -5,7 +5,7 @@ import { fetchText } from "../lib/fetcher.js";
|
|
|
5
5
|
import { collect } from "../lib/fs-utils.js";
|
|
6
6
|
import { loadIndex, saveIndex, sortIndex, upsertSkill } from "../lib/index.js";
|
|
7
7
|
import { recordInstallPaths } from "../lib/installs.js";
|
|
8
|
-
import { isJsonEnabled, printInfo, printJson } from "../lib/output.js";
|
|
8
|
+
import { isJsonEnabled, printInfo, printJson, printSuccess, startSpinner, stopSpinner, } from "../lib/output.js";
|
|
9
9
|
import { buildProjectAgentPaths } from "../lib/project-paths.js";
|
|
10
10
|
import { ensureProjectRegistered, resolveRuntime } from "../lib/runtime.js";
|
|
11
11
|
import { buildMetadata, inferNameFromUrl, parseSkillMarkdown } from "../lib/skill-parser.js";
|
|
@@ -34,17 +34,28 @@ export function registerAdd(program) {
|
|
|
34
34
|
});
|
|
35
35
|
return;
|
|
36
36
|
}
|
|
37
|
+
const showProgress = !isJsonEnabled(options);
|
|
38
|
+
const inferred = inferNameFromUrl(url);
|
|
39
|
+
const displayName = options.name ?? inferred ?? "skill";
|
|
40
|
+
if (showProgress) {
|
|
41
|
+
startSpinner(`Adding ${displayName}`);
|
|
42
|
+
}
|
|
37
43
|
const skillMarkdown = await fetchText(url);
|
|
38
44
|
const parsed = parseSkillMarkdown(skillMarkdown);
|
|
39
|
-
const inferred = inferNameFromUrl(url);
|
|
40
45
|
const skillName = options.name ?? inferred ?? parsed.name;
|
|
41
46
|
if (!skillName) {
|
|
47
|
+
if (showProgress)
|
|
48
|
+
stopSpinner();
|
|
42
49
|
throw new Error("Unable to infer skill name. Use --name to specify it.");
|
|
43
50
|
}
|
|
44
51
|
if (!parsed.name && !options.name) {
|
|
52
|
+
if (showProgress)
|
|
53
|
+
stopSpinner();
|
|
45
54
|
throw new Error("Skill frontmatter missing name. Provide --name to continue.");
|
|
46
55
|
}
|
|
47
56
|
if (!parsed.description) {
|
|
57
|
+
if (showProgress)
|
|
58
|
+
stopSpinner();
|
|
48
59
|
throw new Error("Skill frontmatter missing description. Convert the source into a valid skill.");
|
|
49
60
|
}
|
|
50
61
|
const metadata = buildMetadata(parsed, { type: "url", url }, skillName);
|
|
@@ -102,6 +113,7 @@ export function registerAdd(program) {
|
|
|
102
113
|
});
|
|
103
114
|
await saveIndex(sortIndex(nextIndex));
|
|
104
115
|
if (isJsonEnabled(options)) {
|
|
116
|
+
stopSpinner();
|
|
105
117
|
printJson({
|
|
106
118
|
ok: true,
|
|
107
119
|
command: "add",
|
|
@@ -114,22 +126,8 @@ export function registerAdd(program) {
|
|
|
114
126
|
});
|
|
115
127
|
return;
|
|
116
128
|
}
|
|
117
|
-
|
|
118
|
-
printInfo(
|
|
119
|
-
printInfo("Source: url");
|
|
120
|
-
printInfo(` ${url}`);
|
|
121
|
-
if (installs.length > 0) {
|
|
122
|
-
printInfo("");
|
|
123
|
-
printInfo("Installed to:");
|
|
124
|
-
for (const install of installs) {
|
|
125
|
-
const scopeLabel = install.scope === "project" ? `project:${install.projectRoot}` : "user";
|
|
126
|
-
printInfo(` ✓ ${scopeLabel}/${install.agent}`);
|
|
127
|
-
}
|
|
128
|
-
}
|
|
129
|
-
else {
|
|
130
|
-
printInfo("");
|
|
131
|
-
printInfo("No agent targets were updated.");
|
|
132
|
-
}
|
|
129
|
+
printSuccess(skillName);
|
|
130
|
+
printInfo(`\nAdded skill from ${url}.`);
|
|
133
131
|
}
|
|
134
132
|
catch (error) {
|
|
135
133
|
handleCommandError(options, "add", error);
|
package/dist/commands/list.js
CHANGED
|
@@ -172,6 +172,14 @@ function filterByAgents(skills, agents) {
|
|
|
172
172
|
const agentSet = new Set(agents);
|
|
173
173
|
return skills.filter((skill) => skill.installs?.some((install) => install.agent && agentSet.has(install.agent)));
|
|
174
174
|
}
|
|
175
|
+
function filterUserScope(skills) {
|
|
176
|
+
return skills
|
|
177
|
+
.filter((skill) => skill.installs?.some((install) => install.scope === "user") ?? !skill.installs?.length)
|
|
178
|
+
.map((skill) => ({
|
|
179
|
+
...skill,
|
|
180
|
+
installs: skill.installs?.filter((install) => install.scope === "user"),
|
|
181
|
+
}));
|
|
182
|
+
}
|
|
175
183
|
export function registerList(program) {
|
|
176
184
|
program
|
|
177
185
|
.command("list")
|
|
@@ -186,8 +194,9 @@ export function registerList(program) {
|
|
|
186
194
|
const indexedSkills = options.agents
|
|
187
195
|
? filterByAgents(index.skills, runtime.agentList)
|
|
188
196
|
: index.skills;
|
|
189
|
-
const
|
|
190
|
-
const
|
|
197
|
+
const scopedSkills = options.global ? filterUserScope(indexedSkills) : indexedSkills;
|
|
198
|
+
const mergedSkills = [...scopedSkills, ...globalSkills];
|
|
199
|
+
const enrichedSkills = await enrichWithSubcommands(mergedSkills);
|
|
191
200
|
if (isJsonEnabled(options)) {
|
|
192
201
|
printJson({
|
|
193
202
|
ok: true,
|
package/dist/commands/update.js
CHANGED
|
@@ -4,7 +4,7 @@ import { loadConfig } from "../lib/config.js";
|
|
|
4
4
|
import { fetchText } from "../lib/fetcher.js";
|
|
5
5
|
import { loadIndex, saveIndex, sortIndex, upsertSkill } from "../lib/index.js";
|
|
6
6
|
import { getInstallPaths } from "../lib/installs.js";
|
|
7
|
-
import { isJsonEnabled, printInfo, printJson } from "../lib/output.js";
|
|
7
|
+
import { isJsonEnabled, printFailure, printInfo, printJson, printSkipped, printSuccess, startSpinner, stopSpinner, } from "../lib/output.js";
|
|
8
8
|
import { fetchRepoFile, normalizeRepoRef, writeRepoSkillDirectory } from "../lib/repo-skills.js";
|
|
9
9
|
import { buildMetadata, parseSkillMarkdown } from "../lib/skill-parser.js";
|
|
10
10
|
import { ensureSkillsDir, writeSkillFiles, writeSkillMetadata } from "../lib/skill-store.js";
|
|
@@ -21,31 +21,6 @@ function groupBySource(results) {
|
|
|
21
21
|
failedCount: items.filter((r) => r.status === "failed").length,
|
|
22
22
|
}));
|
|
23
23
|
}
|
|
24
|
-
function formatSourceHeader(group) {
|
|
25
|
-
const count = group.results.length;
|
|
26
|
-
const skillWord = count === 1 ? "skill" : "skills";
|
|
27
|
-
if (group.source === "local") {
|
|
28
|
-
return `${group.source} (${count} ${skillWord} - skipped)`;
|
|
29
|
-
}
|
|
30
|
-
if (group.failedCount > 0) {
|
|
31
|
-
return `${group.source} (${count} ${skillWord}, ${group.failedCount} failed)`;
|
|
32
|
-
}
|
|
33
|
-
return `${group.source} (${count} ${skillWord})`;
|
|
34
|
-
}
|
|
35
|
-
function printSourceGroup(group) {
|
|
36
|
-
printInfo(formatSourceHeader(group));
|
|
37
|
-
for (const result of group.results) {
|
|
38
|
-
if (result.status === "skipped") {
|
|
39
|
-
printInfo(` - ${result.name}`);
|
|
40
|
-
}
|
|
41
|
-
else if (result.status === "failed") {
|
|
42
|
-
printInfo(` ✗ ${result.name} (${result.error ?? "failed"})`);
|
|
43
|
-
}
|
|
44
|
-
else {
|
|
45
|
-
printInfo(` ✓ ${result.name}`);
|
|
46
|
-
}
|
|
47
|
-
}
|
|
48
|
-
}
|
|
49
24
|
async function updateUrlSkill(skill, index, projectRoot, config) {
|
|
50
25
|
if (!skill.source.url) {
|
|
51
26
|
return;
|
|
@@ -129,39 +104,72 @@ export function registerUpdate(program) {
|
|
|
129
104
|
const config = await loadConfig();
|
|
130
105
|
const projectRoot = options.project ? path.resolve(options.project) : null;
|
|
131
106
|
const results = [];
|
|
132
|
-
|
|
107
|
+
const showProgress = !isJsonEnabled(options);
|
|
108
|
+
if (showProgress && targets.length > 0) {
|
|
109
|
+
printInfo(`Updating ${targets.length} skill${targets.length === 1 ? "" : "s"}...\n`);
|
|
110
|
+
}
|
|
111
|
+
const total = targets.length;
|
|
112
|
+
for (let i = 0; i < targets.length; i++) {
|
|
113
|
+
const skill = targets[i];
|
|
114
|
+
const progress = `(${i + 1}/${total})`;
|
|
133
115
|
if (skill.source.type === "url") {
|
|
116
|
+
if (showProgress) {
|
|
117
|
+
startSpinner(`${skill.name} ${progress}`);
|
|
118
|
+
}
|
|
134
119
|
try {
|
|
135
120
|
await updateUrlSkill(skill, index, projectRoot, config);
|
|
136
121
|
results.push({ name: skill.name, source: "url", status: "updated" });
|
|
122
|
+
if (showProgress) {
|
|
123
|
+
printSuccess(skill.name);
|
|
124
|
+
}
|
|
137
125
|
}
|
|
138
126
|
catch (err) {
|
|
127
|
+
const errorMsg = err instanceof Error ? err.message : "unknown error";
|
|
139
128
|
results.push({
|
|
140
129
|
name: skill.name,
|
|
141
130
|
source: "url",
|
|
142
131
|
status: "failed",
|
|
143
|
-
error:
|
|
132
|
+
error: errorMsg,
|
|
144
133
|
});
|
|
134
|
+
if (showProgress) {
|
|
135
|
+
printFailure(skill.name, errorMsg);
|
|
136
|
+
}
|
|
145
137
|
}
|
|
146
138
|
}
|
|
147
139
|
else if (skill.source.type === "git") {
|
|
140
|
+
if (showProgress) {
|
|
141
|
+
startSpinner(`${skill.name} ${progress}`);
|
|
142
|
+
}
|
|
148
143
|
try {
|
|
149
144
|
await updateGitSkill(skill, index, projectRoot, config);
|
|
150
145
|
results.push({ name: skill.name, source: "git", status: "updated" });
|
|
146
|
+
if (showProgress) {
|
|
147
|
+
printSuccess(skill.name);
|
|
148
|
+
}
|
|
151
149
|
}
|
|
152
150
|
catch (err) {
|
|
151
|
+
const errorMsg = err instanceof Error ? err.message : "unknown error";
|
|
153
152
|
results.push({
|
|
154
153
|
name: skill.name,
|
|
155
154
|
source: "git",
|
|
156
155
|
status: "failed",
|
|
157
|
-
error:
|
|
156
|
+
error: errorMsg,
|
|
158
157
|
});
|
|
158
|
+
if (showProgress) {
|
|
159
|
+
printFailure(skill.name, errorMsg);
|
|
160
|
+
}
|
|
159
161
|
}
|
|
160
162
|
}
|
|
161
163
|
else {
|
|
162
164
|
results.push({ name: skill.name, source: skill.source.type, status: "skipped" });
|
|
165
|
+
if (showProgress) {
|
|
166
|
+
printSkipped(skill.name, "skipped");
|
|
167
|
+
}
|
|
163
168
|
}
|
|
164
169
|
}
|
|
170
|
+
if (showProgress) {
|
|
171
|
+
stopSpinner();
|
|
172
|
+
}
|
|
165
173
|
await saveIndex(sortIndex(index));
|
|
166
174
|
const sourceGroups = groupBySource(results);
|
|
167
175
|
const totalUpdated = results.filter((r) => r.status === "updated").length;
|
|
@@ -189,21 +197,15 @@ export function registerUpdate(program) {
|
|
|
189
197
|
printInfo("No skills to update.");
|
|
190
198
|
return;
|
|
191
199
|
}
|
|
192
|
-
printInfo("Skill Update");
|
|
193
|
-
for (const group of sourceGroups) {
|
|
194
|
-
printInfo("");
|
|
195
|
-
printSourceGroup(group);
|
|
196
|
-
}
|
|
197
200
|
// Summary line
|
|
198
|
-
printInfo("");
|
|
199
201
|
if (totalFailed > 0) {
|
|
200
|
-
printInfo(
|
|
202
|
+
printInfo(`\nUpdated ${totalUpdated} of ${totalTrackable} trackable skill${totalTrackable === 1 ? "" : "s"} (${totalFailed} failed).`);
|
|
201
203
|
}
|
|
202
204
|
else if (totalUpdated > 0) {
|
|
203
|
-
printInfo(
|
|
205
|
+
printInfo(`\nUpdated ${totalUpdated} of ${totalTrackable} trackable skill${totalTrackable === 1 ? "" : "s"}.`);
|
|
204
206
|
}
|
|
205
207
|
else if (totalSkipped > 0 && totalTrackable === 0) {
|
|
206
|
-
printInfo("
|
|
208
|
+
printInfo("\nNo trackable skills to update.");
|
|
207
209
|
}
|
|
208
210
|
}
|
|
209
211
|
catch (error) {
|
package/dist/lib/output.js
CHANGED
|
@@ -2,6 +2,48 @@ import chalk from "chalk";
|
|
|
2
2
|
export function isJsonEnabled(options) {
|
|
3
3
|
return Boolean(options.json);
|
|
4
4
|
}
|
|
5
|
+
// Progress indicator support
|
|
6
|
+
const isTTY = process.stdout.isTTY ?? false;
|
|
7
|
+
// Braille spinner frames (single character, smooth animation)
|
|
8
|
+
const SPINNER_FRAMES = ["⠋", "⠙", "⠹", "⠸", "⠼", "⠴", "⠦", "⠧", "⠇", "⠏"];
|
|
9
|
+
let spinnerInterval = null;
|
|
10
|
+
let spinnerFrame = 0;
|
|
11
|
+
export function startSpinner(message) {
|
|
12
|
+
if (!isTTY)
|
|
13
|
+
return;
|
|
14
|
+
spinnerFrame = 0;
|
|
15
|
+
const render = () => {
|
|
16
|
+
const frame = SPINNER_FRAMES[spinnerFrame % SPINNER_FRAMES.length];
|
|
17
|
+
process.stdout.write(`\r\x1b[K ${frame} ${message}`);
|
|
18
|
+
spinnerFrame++;
|
|
19
|
+
};
|
|
20
|
+
render();
|
|
21
|
+
spinnerInterval = setInterval(render, 80);
|
|
22
|
+
}
|
|
23
|
+
export function stopSpinner() {
|
|
24
|
+
if (spinnerInterval) {
|
|
25
|
+
clearInterval(spinnerInterval);
|
|
26
|
+
spinnerInterval = null;
|
|
27
|
+
}
|
|
28
|
+
if (isTTY) {
|
|
29
|
+
process.stdout.write(`\r\x1b[K`);
|
|
30
|
+
}
|
|
31
|
+
}
|
|
32
|
+
export function printProgressResult(message) {
|
|
33
|
+
stopSpinner();
|
|
34
|
+
process.stdout.write(`${message}\n`);
|
|
35
|
+
}
|
|
36
|
+
// Common result formatters for progress output
|
|
37
|
+
export function printSuccess(name, suffix) {
|
|
38
|
+
const msg = suffix ? ` ✓ ${name} (${suffix})` : ` ✓ ${name}`;
|
|
39
|
+
printProgressResult(msg);
|
|
40
|
+
}
|
|
41
|
+
export function printFailure(name, error) {
|
|
42
|
+
printProgressResult(` ✗ ${name} (${error})`);
|
|
43
|
+
}
|
|
44
|
+
export function printSkipped(name, reason) {
|
|
45
|
+
printProgressResult(` - ${name} (${reason})`);
|
|
46
|
+
}
|
|
5
47
|
export function printJson(result) {
|
|
6
48
|
process.stdout.write(`${JSON.stringify(result, null, 2)}\n`);
|
|
7
49
|
}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "skillbox",
|
|
3
|
-
"version": "0.3.
|
|
3
|
+
"version": "0.3.4",
|
|
4
4
|
"description": "Local-first, agent-agnostic skills manager",
|
|
5
5
|
"license": "MIT",
|
|
6
6
|
"author": "Christian Anagnostou",
|
|
@@ -33,6 +33,9 @@
|
|
|
33
33
|
"lint:ci": "oxlint --deny-warnings",
|
|
34
34
|
"format": "oxfmt",
|
|
35
35
|
"format:check": "oxfmt --check",
|
|
36
|
+
"test": "vitest run",
|
|
37
|
+
"test:watch": "vitest",
|
|
38
|
+
"test:ci": "vitest run --reporter=verbose --reporter=junit --outputFile=test-results.xml",
|
|
36
39
|
"prepublishOnly": "npm run lint:ci && npm run format:check && npm run build"
|
|
37
40
|
},
|
|
38
41
|
"dependencies": {
|
|
@@ -43,9 +46,11 @@
|
|
|
43
46
|
},
|
|
44
47
|
"devDependencies": {
|
|
45
48
|
"@types/node": "^20.11.19",
|
|
49
|
+
"execa": "^9.6.1",
|
|
46
50
|
"oxfmt": "^0.16.0",
|
|
47
51
|
"oxlint": "^0.16.0",
|
|
48
52
|
"ts-node": "^10.9.2",
|
|
49
|
-
"typescript": "^5.4.2"
|
|
53
|
+
"typescript": "^5.4.2",
|
|
54
|
+
"vitest": "^4.0.18"
|
|
50
55
|
}
|
|
51
56
|
}
|