skillstogether 0.1.9 → 0.1.11
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/README.md +27 -7
- package/dist/index.js +126 -11
- package/package.json +3 -3
package/README.md
CHANGED
|
@@ -3,12 +3,18 @@
|
|
|
3
3
|
CLI tool to install organization skills from SkillsTogether.
|
|
4
4
|
|
|
5
5
|
```
|
|
6
|
-
███████╗██╗ ██╗██╗██╗ ██╗
|
|
7
|
-
██╔════╝██║ ██╔╝██║██║ ██║
|
|
8
|
-
███████╗█████╔╝ ██║██║ ██║ ███████╗
|
|
9
|
-
╚════██║██╔═██╗ ██║██║ ██║ ╚════██║
|
|
10
|
-
███████║██║ ██╗██║███████╗███████╗███████║
|
|
11
|
-
╚══════╝╚═╝ ╚═╝╚═╝╚══════╝╚══════╝╚══════╝
|
|
6
|
+
███████╗██╗ ██╗██╗██╗ ██╗ ███████╗
|
|
7
|
+
██╔════╝██║ ██╔╝██║██║ ██║ ██╔════╝
|
|
8
|
+
███████╗█████╔╝ ██║██║ ██║ ███████╗
|
|
9
|
+
╚════██║██╔═██╗ ██║██║ ██║ ╚════██║
|
|
10
|
+
███████║██║ ██╗██║███████╗███████╗███████║
|
|
11
|
+
╚══════╝╚═╝ ╚═╝╚═╝╚══════╝╚══════╝╚══════╝
|
|
12
|
+
████████╗ ██████╗ ██████╗ ███████╗████████╗██╗ ██╗███████╗██████╗
|
|
13
|
+
╚══██╔══╝██╔═══██╗██╔════╝ ██╔════╝╚══██╔══╝██║ ██║██╔════╝██╔══██╗
|
|
14
|
+
██║ ██║ ██║██║ ███╗█████╗ ██║ ███████║█████╗ ██████╔╝
|
|
15
|
+
██║ ██║ ██║██║ ██║██╔══╝ ██║ ██╔══██║██╔══╝ ██╔══██╗
|
|
16
|
+
██║ ╚██████╔╝╚██████╔╝███████╗ ██║ ██║ ██║███████╗██║ ██║
|
|
17
|
+
╚═╝ ╚═════╝ ╚═════╝ ╚══════╝ ╚═╝ ╚═╝ ╚═╝╚══════╝╚═╝ ╚═╝
|
|
12
18
|
```
|
|
13
19
|
|
|
14
20
|
## Installation
|
|
@@ -69,6 +75,20 @@ npx skillstogether uninstall <organization-slug> --skill <skill-slug>
|
|
|
69
75
|
|
|
70
76
|
```
|
|
71
77
|
|
|
78
|
+
### Updating Skills
|
|
79
|
+
|
|
80
|
+
```bash
|
|
81
|
+
# Update all installed skills
|
|
82
|
+
npx skillstogether update
|
|
83
|
+
|
|
84
|
+
# Update all skills from an organization
|
|
85
|
+
npx skillstogether update <organization-slug>
|
|
86
|
+
|
|
87
|
+
# Update a specific skill (skill slug already includes the org prefix)
|
|
88
|
+
npx skillstogether update <organization-slug> --skill <skill-slug>
|
|
89
|
+
|
|
90
|
+
```
|
|
91
|
+
|
|
72
92
|
### Options
|
|
73
93
|
|
|
74
94
|
| Option | Alias | Description |
|
|
@@ -76,7 +96,7 @@ npx skillstogether uninstall <organization-slug> --skill <skill-slug>
|
|
|
76
96
|
| `--dir <path>` | `-d` | Custom installation directory |
|
|
77
97
|
| `--force` | `-f` | Overwrite existing skill files |
|
|
78
98
|
| `--yes` | `-y` | Skip interactive prompts, install all |
|
|
79
|
-
| `--skill <slug>` | — |
|
|
99
|
+
| `--skill <slug>` | — | Target a specific skill by slug (org-prefixed) |
|
|
80
100
|
| `--global` | — | Install globally (in home directory) |
|
|
81
101
|
|
|
82
102
|
---
|
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]+)*$/;
|
|
@@ -328,13 +400,23 @@ var addTargetSchema = z.string().min(1, "Target is required").refine(
|
|
|
328
400
|
},
|
|
329
401
|
{ message: "Each part must be a valid slug (lowercase, numbers, hyphens)" }
|
|
330
402
|
);
|
|
331
|
-
var updateTargetSchema = z.string().max(
|
|
403
|
+
var updateTargetSchema = z.string().max(100).optional().refine(
|
|
332
404
|
(val) => {
|
|
333
405
|
if (!val) return true;
|
|
334
406
|
const parts = val.split("/");
|
|
335
|
-
return parts.length
|
|
407
|
+
return parts.length === 1;
|
|
336
408
|
},
|
|
337
|
-
{
|
|
409
|
+
{
|
|
410
|
+
message: "Target must be an organization slug (no '/'). Use --skill to target a specific skill."
|
|
411
|
+
}
|
|
412
|
+
).refine(
|
|
413
|
+
(val) => {
|
|
414
|
+
if (!val) return true;
|
|
415
|
+
return slugRegex.test(val);
|
|
416
|
+
},
|
|
417
|
+
{
|
|
418
|
+
message: "Organization slug must be lowercase letters, numbers, and hyphens only"
|
|
419
|
+
}
|
|
338
420
|
);
|
|
339
421
|
var uninstallTargetSchema = z.string().min(1, "Target is required").refine(
|
|
340
422
|
(val) => {
|
|
@@ -355,10 +437,9 @@ function parseUpdateTarget(target) {
|
|
|
355
437
|
if (target === void 0 || target === "") return {};
|
|
356
438
|
const parsed = updateTargetSchema.parse(target);
|
|
357
439
|
if (!parsed || typeof parsed !== "string") return {};
|
|
358
|
-
const
|
|
440
|
+
const organizationSlug = organizationSlugSchema.parse(parsed);
|
|
359
441
|
return {
|
|
360
|
-
organizationSlug
|
|
361
|
-
skillSlug: parts.length === 2 ? parts[1] : void 0
|
|
442
|
+
organizationSlug
|
|
362
443
|
};
|
|
363
444
|
}
|
|
364
445
|
function parseUninstallTarget(target) {
|
|
@@ -406,7 +487,11 @@ function generateSkillContent(skill, organizationSlug, filesChecksum) {
|
|
|
406
487
|
filesChecksum ? `filesChecksum: ${filesChecksum}` : null,
|
|
407
488
|
"---"
|
|
408
489
|
].filter((line) => line !== null && line !== void 0).join("\n");
|
|
409
|
-
const body =
|
|
490
|
+
const body = normalizeFeedbackContent(
|
|
491
|
+
skill.content,
|
|
492
|
+
skill.slug,
|
|
493
|
+
skill.feedbackEnabled
|
|
494
|
+
);
|
|
410
495
|
const separator = body ? body.startsWith("\n") || body.startsWith("\r\n") ? "\n" : "\n\n" : "\n";
|
|
411
496
|
const content = frontmatter + separator + body;
|
|
412
497
|
return content.endsWith("\n") ? content : `${content}
|
|
@@ -2638,9 +2723,17 @@ function generateUpdatedContent(skill, organizationSlug) {
|
|
|
2638
2723
|
createdBy: skill.createdBy.name,
|
|
2639
2724
|
installedAt: (/* @__PURE__ */ new Date()).toISOString()
|
|
2640
2725
|
});
|
|
2641
|
-
|
|
2726
|
+
const normalizedContent = normalizeFeedbackContent(
|
|
2727
|
+
skill.content,
|
|
2728
|
+
skill.slug,
|
|
2729
|
+
skill.feedbackEnabled
|
|
2730
|
+
);
|
|
2731
|
+
return frontmatter + "\n" + normalizedContent;
|
|
2642
2732
|
}
|
|
2643
|
-
var updateCommand = new Command8("update").description("Update installed skills to latest version").argument("[target]", "Organization slug
|
|
2733
|
+
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(
|
|
2734
|
+
"--skill <slug>",
|
|
2735
|
+
"Update a specific skill by slug (already org-prefixed, e.g. acme-onboarding)"
|
|
2736
|
+
).option("-y, --yes", "Skip confirmation prompts").option("--dry-run", "Show what would be updated without making changes").action(
|
|
2644
2737
|
async (target, options) => {
|
|
2645
2738
|
printCompactBanner();
|
|
2646
2739
|
p9.intro(pc10.bgCyan(pc10.black(" Update Skills ")));
|
|
@@ -2659,12 +2752,10 @@ var updateCommand = new Command8("update").description("Update installed skills
|
|
|
2659
2752
|
scope = "project";
|
|
2660
2753
|
}
|
|
2661
2754
|
let organizationSlug;
|
|
2662
|
-
let skillSlug;
|
|
2663
2755
|
if (target) {
|
|
2664
2756
|
try {
|
|
2665
2757
|
const parsed = parseUpdateTarget(target);
|
|
2666
2758
|
organizationSlug = parsed.organizationSlug;
|
|
2667
|
-
skillSlug = parsed.skillSlug;
|
|
2668
2759
|
} catch (err) {
|
|
2669
2760
|
const msg = err instanceof Error && "message" in err ? err.message : "Invalid target format";
|
|
2670
2761
|
p9.log.error(msg);
|
|
@@ -2672,6 +2763,30 @@ var updateCommand = new Command8("update").description("Update installed skills
|
|
|
2672
2763
|
process.exit(1);
|
|
2673
2764
|
}
|
|
2674
2765
|
}
|
|
2766
|
+
if (options.skill && !organizationSlug) {
|
|
2767
|
+
p9.log.error("Organization slug is required when using --skill");
|
|
2768
|
+
p9.outro(pc10.red("Invalid format"));
|
|
2769
|
+
process.exit(1);
|
|
2770
|
+
}
|
|
2771
|
+
let skillSlug;
|
|
2772
|
+
if (options.skill) {
|
|
2773
|
+
const skillResult = skillSlugSchema.safeParse(options.skill);
|
|
2774
|
+
if (!skillResult.success) {
|
|
2775
|
+
const msg = skillResult.error.issues?.[0]?.message ?? skillResult.error.message ?? "Invalid skill slug";
|
|
2776
|
+
p9.log.error(msg);
|
|
2777
|
+
p9.outro(pc10.red("Invalid format"));
|
|
2778
|
+
process.exit(1);
|
|
2779
|
+
}
|
|
2780
|
+
const expectedPrefix = `${organizationSlug}-`;
|
|
2781
|
+
if (!skillResult.data.startsWith(expectedPrefix)) {
|
|
2782
|
+
p9.log.error(
|
|
2783
|
+
`Skill slug must be prefixed with the organization slug (e.g., ${pc10.cyan(`${expectedPrefix}my-skill`)})`
|
|
2784
|
+
);
|
|
2785
|
+
p9.outro(pc10.red("Invalid format"));
|
|
2786
|
+
process.exit(1);
|
|
2787
|
+
}
|
|
2788
|
+
skillSlug = skillResult.data;
|
|
2789
|
+
}
|
|
2675
2790
|
const s = p9.spinner();
|
|
2676
2791
|
s.start("Scanning installed skills...");
|
|
2677
2792
|
const allInstalledSkills = scanInstalledSkills({
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "skillstogether",
|
|
3
|
-
"version": "0.1.
|
|
3
|
+
"version": "0.1.11",
|
|
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
|
},
|