skillstogether 0.1.10 → 0.1.12
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/index.js +191 -21
- package/package.json +3 -3
package/dist/index.js
CHANGED
|
@@ -302,6 +302,78 @@ function formatErrorMessage(err, fallback = DEFAULT_ERROR_MESSAGE) {
|
|
|
302
302
|
import { existsSync as existsSync2, mkdirSync as mkdirSync2, writeFileSync as writeFileSync2 } from "fs";
|
|
303
303
|
import { dirname, join as join2 } from "path";
|
|
304
304
|
|
|
305
|
+
// src/lib/feedback-content.ts
|
|
306
|
+
var FEEDBACK_SECTION_HEADER = "## Post-Task Reporting";
|
|
307
|
+
function detectEol(content) {
|
|
308
|
+
return content.includes("\r\n") ? "\r\n" : "\n";
|
|
309
|
+
}
|
|
310
|
+
function removeTrailingFeedbackSection(content) {
|
|
311
|
+
const trailingSectionPattern = /^([\s\S]*)(?:\r?\n---\r?\n\r?\n## Post-Task Reporting\b[\s\S]*)$/;
|
|
312
|
+
const withPrefixMatch = content.match(trailingSectionPattern);
|
|
313
|
+
if (withPrefixMatch) {
|
|
314
|
+
return withPrefixMatch[1]?.trimEnd() ?? "";
|
|
315
|
+
}
|
|
316
|
+
const fullSectionPattern = /^---\r?\n\r?\n## Post-Task Reporting\b[\s\S]*$/;
|
|
317
|
+
if (fullSectionPattern.test(content)) {
|
|
318
|
+
return "";
|
|
319
|
+
}
|
|
320
|
+
return content;
|
|
321
|
+
}
|
|
322
|
+
function getFeedbackReportingSection(skillSlug) {
|
|
323
|
+
return [
|
|
324
|
+
"---",
|
|
325
|
+
"",
|
|
326
|
+
FEEDBACK_SECTION_HEADER,
|
|
327
|
+
"",
|
|
328
|
+
"After completing this skill's task, report your results using the CLI:",
|
|
329
|
+
"",
|
|
330
|
+
"```bash",
|
|
331
|
+
`npx skillstogether feedback ${skillSlug} \\`,
|
|
332
|
+
" --success \\",
|
|
333
|
+
" --quality 4 \\",
|
|
334
|
+
' --summary "Brief description of what was accomplished" \\',
|
|
335
|
+
' --agent "cursor"',
|
|
336
|
+
"```",
|
|
337
|
+
"",
|
|
338
|
+
"### Options",
|
|
339
|
+
"| Flag | Description |",
|
|
340
|
+
"|------|-------------|",
|
|
341
|
+
"| `--success` / `--failed` | Whether the task succeeded |",
|
|
342
|
+
"| `-q, --quality <1-5>` | Quality self-assessment |",
|
|
343
|
+
"| `-t, --time <seconds>` | Time spent |",
|
|
344
|
+
"| `-c, --files-count <n>` | Files modified |",
|
|
345
|
+
"| `-m, --summary <text>` | Summary of work |",
|
|
346
|
+
"| `--challenges <text>` | Difficulties encountered |",
|
|
347
|
+
"| `-a, --agent <name>` | Agent name (cursor, claude, codex) |",
|
|
348
|
+
"",
|
|
349
|
+
"If not authenticated, skip reporting silently."
|
|
350
|
+
].join("\n");
|
|
351
|
+
}
|
|
352
|
+
function hasFeedbackSection(content) {
|
|
353
|
+
return (content ?? "").includes(FEEDBACK_SECTION_HEADER);
|
|
354
|
+
}
|
|
355
|
+
function normalizeFeedbackContent(content, skillSlug, feedbackEnabled) {
|
|
356
|
+
const text = content ?? "";
|
|
357
|
+
if (!feedbackEnabled) {
|
|
358
|
+
return removeTrailingFeedbackSection(text);
|
|
359
|
+
}
|
|
360
|
+
if (hasFeedbackSection(text)) {
|
|
361
|
+
return text;
|
|
362
|
+
}
|
|
363
|
+
const eol = detectEol(text);
|
|
364
|
+
const section = getFeedbackReportingSection(skillSlug).replace(/\n/g, eol);
|
|
365
|
+
if (text.length === 0) {
|
|
366
|
+
return section;
|
|
367
|
+
}
|
|
368
|
+
if (/(?:\r?\n){2}$/.test(text)) {
|
|
369
|
+
return text + section;
|
|
370
|
+
}
|
|
371
|
+
if (/\r?\n$/.test(text)) {
|
|
372
|
+
return text + eol + section;
|
|
373
|
+
}
|
|
374
|
+
return text + eol + eol + section;
|
|
375
|
+
}
|
|
376
|
+
|
|
305
377
|
// src/lib/validation.ts
|
|
306
378
|
import { z } from "zod";
|
|
307
379
|
var slugRegex = /^[a-z0-9]+(?:-[a-z0-9]+)*$/;
|
|
@@ -415,7 +487,11 @@ function generateSkillContent(skill, organizationSlug, filesChecksum) {
|
|
|
415
487
|
filesChecksum ? `filesChecksum: ${filesChecksum}` : null,
|
|
416
488
|
"---"
|
|
417
489
|
].filter((line) => line !== null && line !== void 0).join("\n");
|
|
418
|
-
const body =
|
|
490
|
+
const body = normalizeFeedbackContent(
|
|
491
|
+
skill.content,
|
|
492
|
+
skill.slug,
|
|
493
|
+
skill.feedbackEnabled
|
|
494
|
+
);
|
|
419
495
|
const separator = body ? body.startsWith("\n") || body.startsWith("\r\n") ? "\n" : "\n\n" : "\n";
|
|
420
496
|
const content = frontmatter + separator + body;
|
|
421
497
|
return content.endsWith("\n") ? content : `${content}
|
|
@@ -2636,7 +2712,8 @@ async function uninstallSkill(organizationSlug, skillSlug, scope, skipConfirm) {
|
|
|
2636
2712
|
// src/commands/update.ts
|
|
2637
2713
|
import * as p9 from "@clack/prompts";
|
|
2638
2714
|
import { Command as Command8 } from "commander";
|
|
2639
|
-
import { writeFileSync as writeFileSync3 } from "fs";
|
|
2715
|
+
import { rmSync as rmSync2, writeFileSync as writeFileSync3 } from "fs";
|
|
2716
|
+
import { basename as basename2, dirname as dirname3 } from "path";
|
|
2640
2717
|
import pc10 from "picocolors";
|
|
2641
2718
|
function generateUpdatedContent(skill, organizationSlug) {
|
|
2642
2719
|
const frontmatter = generateFrontmatter({
|
|
@@ -2647,7 +2724,31 @@ function generateUpdatedContent(skill, organizationSlug) {
|
|
|
2647
2724
|
createdBy: skill.createdBy.name,
|
|
2648
2725
|
installedAt: (/* @__PURE__ */ new Date()).toISOString()
|
|
2649
2726
|
});
|
|
2650
|
-
|
|
2727
|
+
const normalizedContent = normalizeFeedbackContent(
|
|
2728
|
+
skill.content,
|
|
2729
|
+
skill.slug,
|
|
2730
|
+
skill.feedbackEnabled
|
|
2731
|
+
);
|
|
2732
|
+
return frontmatter + "\n" + normalizedContent;
|
|
2733
|
+
}
|
|
2734
|
+
function removeInstalledSkillPath(skillPath) {
|
|
2735
|
+
try {
|
|
2736
|
+
if (basename2(skillPath) === "SKILL.md") {
|
|
2737
|
+
rmSync2(dirname3(skillPath), { recursive: true, force: true });
|
|
2738
|
+
} else {
|
|
2739
|
+
rmSync2(skillPath, { force: true });
|
|
2740
|
+
try {
|
|
2741
|
+
rmSync2(dirname3(skillPath), { recursive: false });
|
|
2742
|
+
} catch {
|
|
2743
|
+
}
|
|
2744
|
+
}
|
|
2745
|
+
return { success: true };
|
|
2746
|
+
} catch (error) {
|
|
2747
|
+
return {
|
|
2748
|
+
success: false,
|
|
2749
|
+
error: formatErrorMessage(error)
|
|
2750
|
+
};
|
|
2751
|
+
}
|
|
2651
2752
|
}
|
|
2652
2753
|
var updateCommand = new Command8("update").description("Update installed skills to latest version").argument("[target]", "Organization slug").option("--global", "Update only globally installed skills").option("--project", "Update only project-installed skills").option(
|
|
2653
2754
|
"--skill <slug>",
|
|
@@ -2737,6 +2838,7 @@ var updateCommand = new Command8("update").description("Update installed skills
|
|
|
2737
2838
|
const checkSpinner = p9.spinner();
|
|
2738
2839
|
checkSpinner.start("Checking for updates...");
|
|
2739
2840
|
const skillsToUpdate = [];
|
|
2841
|
+
const skillsToRemove = [];
|
|
2740
2842
|
const errors = [];
|
|
2741
2843
|
for (const [org, skills] of byOrg) {
|
|
2742
2844
|
try {
|
|
@@ -2745,6 +2847,7 @@ var updateCommand = new Command8("update").description("Update installed skills
|
|
|
2745
2847
|
installedAt: s2.installedAt
|
|
2746
2848
|
}));
|
|
2747
2849
|
const result = await checkForUpdates(org, skillsInfo);
|
|
2850
|
+
const remoteSlugs = new Set(result.updates.map((update) => update.slug));
|
|
2748
2851
|
for (const update of result.updates) {
|
|
2749
2852
|
if (update.hasUpdate) {
|
|
2750
2853
|
const unique = skills.find((s2) => s2.slug === update.slug);
|
|
@@ -2757,12 +2860,17 @@ var updateCommand = new Command8("update").description("Update installed skills
|
|
|
2757
2860
|
}
|
|
2758
2861
|
}
|
|
2759
2862
|
}
|
|
2863
|
+
for (const unique of skills) {
|
|
2864
|
+
if (!remoteSlugs.has(unique.slug)) {
|
|
2865
|
+
skillsToRemove.push({ unique });
|
|
2866
|
+
}
|
|
2867
|
+
}
|
|
2760
2868
|
} catch (error) {
|
|
2761
2869
|
errors.push(`${org}: ${formatErrorMessage(error)}`);
|
|
2762
2870
|
}
|
|
2763
2871
|
}
|
|
2764
2872
|
checkSpinner.stop("Update check complete");
|
|
2765
|
-
if (skillsToUpdate.length === 0) {
|
|
2873
|
+
if (skillsToUpdate.length === 0 && skillsToRemove.length === 0) {
|
|
2766
2874
|
p9.log.success("All skills are up to date!");
|
|
2767
2875
|
if (errors.length > 0) {
|
|
2768
2876
|
console.log();
|
|
@@ -2776,19 +2884,38 @@ var updateCommand = new Command8("update").description("Update installed skills
|
|
|
2776
2884
|
p9.outro(pc10.dim("Done"));
|
|
2777
2885
|
return;
|
|
2778
2886
|
}
|
|
2779
|
-
const
|
|
2887
|
+
const totalUpdatedInstances = skillsToUpdate.reduce(
|
|
2780
2888
|
(sum, s2) => sum + s2.unique.paths.length,
|
|
2781
2889
|
0
|
|
2782
2890
|
);
|
|
2783
|
-
|
|
2784
|
-
|
|
2785
|
-
|
|
2786
|
-
|
|
2787
|
-
|
|
2788
|
-
|
|
2789
|
-
console.log(
|
|
2790
|
-
|
|
2791
|
-
);
|
|
2891
|
+
const totalRemovedInstances = skillsToRemove.reduce(
|
|
2892
|
+
(sum, s2) => sum + s2.unique.paths.length,
|
|
2893
|
+
0
|
|
2894
|
+
);
|
|
2895
|
+
const totalAffectedInstances = totalUpdatedInstances + totalRemovedInstances;
|
|
2896
|
+
if (skillsToUpdate.length > 0) {
|
|
2897
|
+
console.log();
|
|
2898
|
+
const updateMsg = skillsToUpdate.length === totalUpdatedInstances ? `${pc10.yellow(skillsToUpdate.length.toString())} skill${skillsToUpdate.length !== 1 ? "s" : ""} will be updated:` : `${pc10.yellow(skillsToUpdate.length.toString())} skill${skillsToUpdate.length !== 1 ? "s" : ""} (${totalUpdatedInstances} installations) will be updated:`;
|
|
2899
|
+
p9.log.info(updateMsg);
|
|
2900
|
+
for (const { unique, remoteVersion } of skillsToUpdate) {
|
|
2901
|
+
const agentNames = unique.agents.map((a) => a.name).join(", ");
|
|
2902
|
+
const scopeBadge = unique.scope === "global" ? pc10.yellow("(global)") : pc10.dim("(project)");
|
|
2903
|
+
console.log(
|
|
2904
|
+
` ${pc10.yellow("\u2191")} ${pc10.white(`${unique.organization}/${unique.slug}`)} ${pc10.dim(`v${unique.version || "?"}`)} \u2192 ${pc10.green(`v${remoteVersion}`)} ${pc10.dim(`[${agentNames}]`)} ${scopeBadge}`
|
|
2905
|
+
);
|
|
2906
|
+
}
|
|
2907
|
+
}
|
|
2908
|
+
if (skillsToRemove.length > 0) {
|
|
2909
|
+
console.log();
|
|
2910
|
+
const removeMsg = skillsToRemove.length === totalRemovedInstances ? `${pc10.red(skillsToRemove.length.toString())} skill${skillsToRemove.length !== 1 ? "s" : ""} deleted from remote will be removed locally:` : `${pc10.red(skillsToRemove.length.toString())} skill${skillsToRemove.length !== 1 ? "s" : ""} deleted from remote will be removed locally (${totalRemovedInstances} installations):`;
|
|
2911
|
+
p9.log.warn(removeMsg);
|
|
2912
|
+
for (const { unique } of skillsToRemove) {
|
|
2913
|
+
const agentNames = unique.agents.map((a) => a.name).join(", ");
|
|
2914
|
+
const scopeBadge = unique.scope === "global" ? pc10.yellow("(global)") : pc10.dim("(project)");
|
|
2915
|
+
console.log(
|
|
2916
|
+
` ${pc10.red("\u2193")} ${pc10.white(`${unique.organization}/${unique.slug}`)} ${pc10.dim(`[${agentNames}]`)} ${scopeBadge}`
|
|
2917
|
+
);
|
|
2918
|
+
}
|
|
2792
2919
|
}
|
|
2793
2920
|
console.log();
|
|
2794
2921
|
if (options.dryRun) {
|
|
@@ -2797,7 +2924,15 @@ var updateCommand = new Command8("update").description("Update installed skills
|
|
|
2797
2924
|
return;
|
|
2798
2925
|
}
|
|
2799
2926
|
if (!options.yes) {
|
|
2800
|
-
|
|
2927
|
+
let confirmMsg;
|
|
2928
|
+
if (skillsToUpdate.length > 0 && skillsToRemove.length > 0) {
|
|
2929
|
+
const noun = totalAffectedInstances === 1 ? "installation" : "installations";
|
|
2930
|
+
confirmMsg = `Apply ${skillsToUpdate.length} update${skillsToUpdate.length !== 1 ? "s" : ""} and remove ${skillsToRemove.length} deleted skill${skillsToRemove.length !== 1 ? "s" : ""} (${totalAffectedInstances} ${noun})?`;
|
|
2931
|
+
} else if (skillsToUpdate.length > 0) {
|
|
2932
|
+
confirmMsg = skillsToUpdate.length === totalUpdatedInstances ? `Update ${skillsToUpdate.length} skill${skillsToUpdate.length !== 1 ? "s" : ""}?` : `Update ${skillsToUpdate.length} skill${skillsToUpdate.length !== 1 ? "s" : ""} (${totalUpdatedInstances} installations)?`;
|
|
2933
|
+
} else {
|
|
2934
|
+
confirmMsg = skillsToRemove.length === totalRemovedInstances ? `Remove ${skillsToRemove.length} deleted skill${skillsToRemove.length !== 1 ? "s" : ""} locally?` : `Remove ${skillsToRemove.length} deleted skill${skillsToRemove.length !== 1 ? "s" : ""} locally (${totalRemovedInstances} installations)?`;
|
|
2935
|
+
}
|
|
2801
2936
|
const confirmed = await p9.confirm({
|
|
2802
2937
|
message: confirmMsg,
|
|
2803
2938
|
initialValue: true
|
|
@@ -2808,11 +2943,15 @@ var updateCommand = new Command8("update").description("Update installed skills
|
|
|
2808
2943
|
}
|
|
2809
2944
|
}
|
|
2810
2945
|
const updateSpinner = p9.spinner();
|
|
2811
|
-
updateSpinner.start("
|
|
2946
|
+
updateSpinner.start("Applying changes...");
|
|
2812
2947
|
let updatedSkills = 0;
|
|
2813
2948
|
let updatedInstances = 0;
|
|
2814
|
-
let
|
|
2949
|
+
let updateFailed = 0;
|
|
2815
2950
|
const updateErrors = [];
|
|
2951
|
+
let removedSkills = 0;
|
|
2952
|
+
let removedInstances = 0;
|
|
2953
|
+
let removalFailed = 0;
|
|
2954
|
+
const removalErrors = [];
|
|
2816
2955
|
for (const { unique } of skillsToUpdate) {
|
|
2817
2956
|
try {
|
|
2818
2957
|
const skill = await fetchSkill(unique.organization, unique.slug);
|
|
@@ -2823,25 +2962,56 @@ var updateCommand = new Command8("update").description("Update installed skills
|
|
|
2823
2962
|
}
|
|
2824
2963
|
updatedSkills++;
|
|
2825
2964
|
} catch (error) {
|
|
2826
|
-
|
|
2965
|
+
updateFailed++;
|
|
2827
2966
|
updateErrors.push(
|
|
2828
2967
|
`${unique.organization}/${unique.slug}: ${formatErrorMessage(error)}`
|
|
2829
2968
|
);
|
|
2830
2969
|
}
|
|
2831
2970
|
}
|
|
2832
|
-
|
|
2971
|
+
for (const { unique } of skillsToRemove) {
|
|
2972
|
+
let allInstancesRemoved = true;
|
|
2973
|
+
for (const path of unique.paths) {
|
|
2974
|
+
const result = removeInstalledSkillPath(path);
|
|
2975
|
+
if (result.success) {
|
|
2976
|
+
removedInstances++;
|
|
2977
|
+
} else {
|
|
2978
|
+
allInstancesRemoved = false;
|
|
2979
|
+
removalErrors.push(
|
|
2980
|
+
`${unique.organization}/${unique.slug} (${path}): ${result.error}`
|
|
2981
|
+
);
|
|
2982
|
+
}
|
|
2983
|
+
}
|
|
2984
|
+
if (allInstancesRemoved) {
|
|
2985
|
+
removedSkills++;
|
|
2986
|
+
} else {
|
|
2987
|
+
removalFailed++;
|
|
2988
|
+
}
|
|
2989
|
+
}
|
|
2990
|
+
updateSpinner.stop("Changes applied");
|
|
2833
2991
|
if (updatedSkills > 0) {
|
|
2834
2992
|
const summaryMsg = updatedSkills === updatedInstances ? `Updated ${pc10.green(updatedSkills.toString())} skill${updatedSkills !== 1 ? "s" : ""}` : `Updated ${pc10.green(updatedSkills.toString())} skill${updatedSkills !== 1 ? "s" : ""} (${updatedInstances} installations)`;
|
|
2835
2993
|
p9.log.success(summaryMsg);
|
|
2836
2994
|
}
|
|
2837
|
-
if (
|
|
2995
|
+
if (updateFailed > 0) {
|
|
2838
2996
|
p9.log.error(
|
|
2839
|
-
`Failed to update ${pc10.red(
|
|
2997
|
+
`Failed to update ${pc10.red(updateFailed.toString())} skill${updateFailed !== 1 ? "s" : ""}`
|
|
2840
2998
|
);
|
|
2841
2999
|
for (const error of updateErrors) {
|
|
2842
3000
|
console.log(` ${pc10.red("\u2022")} ${error}`);
|
|
2843
3001
|
}
|
|
2844
3002
|
}
|
|
3003
|
+
if (removedSkills > 0) {
|
|
3004
|
+
const summaryMsg = removedSkills === removedInstances ? `Removed ${pc10.green(removedSkills.toString())} deleted skill${removedSkills !== 1 ? "s" : ""}` : `Removed ${pc10.green(removedSkills.toString())} deleted skill${removedSkills !== 1 ? "s" : ""} (${removedInstances} installations)`;
|
|
3005
|
+
p9.log.success(summaryMsg);
|
|
3006
|
+
}
|
|
3007
|
+
if (removalFailed > 0) {
|
|
3008
|
+
p9.log.error(
|
|
3009
|
+
`Failed to remove ${pc10.red(removalFailed.toString())} deleted skill${removalFailed !== 1 ? "s" : ""}`
|
|
3010
|
+
);
|
|
3011
|
+
for (const error of removalErrors) {
|
|
3012
|
+
console.log(` ${pc10.red("\u2022")} ${error}`);
|
|
3013
|
+
}
|
|
3014
|
+
}
|
|
2845
3015
|
p9.outro(pc10.dim("Done"));
|
|
2846
3016
|
}
|
|
2847
3017
|
);
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "skillstogether",
|
|
3
|
-
"version": "0.1.
|
|
3
|
+
"version": "0.1.12",
|
|
4
4
|
"description": "CLI tool to install skills",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"cli",
|
|
@@ -19,14 +19,14 @@
|
|
|
19
19
|
"access": "public"
|
|
20
20
|
},
|
|
21
21
|
"dependencies": {
|
|
22
|
-
"@clack/prompts": "^1.0.
|
|
22
|
+
"@clack/prompts": "^1.0.1",
|
|
23
23
|
"commander": "^14.0.3",
|
|
24
24
|
"open": "^11.0.0",
|
|
25
25
|
"picocolors": "^1.1.1",
|
|
26
26
|
"zod": "^4.3.6"
|
|
27
27
|
},
|
|
28
28
|
"devDependencies": {
|
|
29
|
-
"@types/node": "^25.2.
|
|
29
|
+
"@types/node": "^25.2.3",
|
|
30
30
|
"tsup": "^8.5.1",
|
|
31
31
|
"typescript": "^5.9.3"
|
|
32
32
|
},
|