@baselane/packs 0.1.1 → 0.1.3

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.
@@ -4,6 +4,12 @@ const VERSION_TAG_RE = /^v?(\d+\.\d+\.\d+)$/;
4
4
  const ONE_LEVEL_SKILL_RE = /^skills\/([^/]+)\/SKILL\.md$/;
5
5
  const TWO_LEVEL_SKILL_RE = /^skills\/([^/]+)\/([^/]+)\/SKILL\.md$/;
6
6
  const AGENTS_SKILL_RE = /^\.agents\/skills\/([^/]+)\/SKILL\.md$/;
7
+ // gstack layout: every non-dot top-level dir holding a SKILL.md is a skill (autoplan/SKILL.md,
8
+ // careful/SKILL.md, ...). Dot dirs are excluded so .github/ etc. can never smuggle a skill in.
9
+ const TOP_LEVEL_SKILL_RE = /^([^./][^/]*)\/SKILL\.md$/;
10
+ // Claude plugin-marketplace layout (trailofbits/skills, anthropics/claude-code, expo/skills):
11
+ // plugins/<plugin>/skills/<name>/SKILL.md.
12
+ const PLUGIN_SKILL_RE = /^plugins\/([^/]+)\/skills\/([^/]+)\/SKILL\.md$/;
7
13
  const ROOT_SKILL_PATH = "SKILL.md";
8
14
  function stampVersion(ref, sha) {
9
15
  const m = VERSION_TAG_RE.exec(ref);
@@ -29,6 +35,8 @@ function findSkillMatches(paths, repoName) {
29
35
  const oneLevel = ONE_LEVEL_SKILL_RE.exec(path);
30
36
  const twoLevel = !oneLevel ? TWO_LEVEL_SKILL_RE.exec(path) : null;
31
37
  const agentsLevel = !oneLevel && !twoLevel ? AGENTS_SKILL_RE.exec(path) : null;
38
+ const pluginLevel = !oneLevel && !twoLevel && !agentsLevel ? PLUGIN_SKILL_RE.exec(path) : null;
39
+ const topLevel = !oneLevel && !twoLevel && !agentsLevel && !pluginLevel ? TOP_LEVEL_SKILL_RE.exec(path) : null;
32
40
  if (oneLevel) {
33
41
  name = oneLevel[1];
34
42
  sourceDir = `skills/${oneLevel[1]}`;
@@ -41,6 +49,14 @@ function findSkillMatches(paths, repoName) {
41
49
  name = agentsLevel[1];
42
50
  sourceDir = `.agents/skills/${agentsLevel[1]}`;
43
51
  }
52
+ else if (pluginLevel) {
53
+ name = pluginLevel[2];
54
+ sourceDir = `plugins/${pluginLevel[1]}/skills/${pluginLevel[2]}`;
55
+ }
56
+ else if (topLevel) {
57
+ name = topLevel[1];
58
+ sourceDir = topLevel[1];
59
+ }
44
60
  }
45
61
  if (name === null)
46
62
  continue;
@@ -2,7 +2,7 @@ import type { Capability, PackAgent, PackCommand, PackHook, PackScope, SkillBloc
2
2
  export declare const KNOWN_HOOK_EVENTS: readonly ["PreToolUse", "PostToolUse", "Notification", "UserPromptSubmit", "Stop", "SubagentStop", "PreCompact", "SessionStart", "SessionEnd"];
3
3
  export declare const SKILL_NAME_MAX = 64;
4
4
  export declare const SKILL_DESC_MAX = 1024;
5
- export declare const SKILL_BODY_MAX_LINES = 500;
5
+ export declare const SKILL_BODY_MAX_LINES = 5000;
6
6
  export declare const SKILL_BODY_WARN_LINES = 400;
7
7
  export interface SkillLint {
8
8
  field: string;
package/dist/validate.js CHANGED
@@ -258,7 +258,10 @@ function onboarding(v) {
258
258
  }
259
259
  export const SKILL_NAME_MAX = 64;
260
260
  export const SKILL_DESC_MAX = 1024;
261
- export const SKILL_BODY_MAX_LINES = 500;
261
+ // Hard ceiling is a sanity bound, not an authoring target — real ecosystem skills routinely run
262
+ // 1-2k lines (garrytan/gstack's spec/SKILL.md is ~2.4k), and ingest must not reject them. The
263
+ // 400-line soft warning below is the authoring-quality nudge.
264
+ export const SKILL_BODY_MAX_LINES = 5000;
262
265
  export const SKILL_BODY_WARN_LINES = 400;
263
266
  const XML_TAG = /<\/?[a-zA-Z][^>]*>/;
264
267
  /** name: slug, ≤64 chars. A name containing "anthropic"/"claude" is NOT rejected here — that
@@ -283,7 +286,7 @@ function skillDescription(obj, path) {
283
286
  fail(`${path}.description`, "free of XML tags");
284
287
  return v;
285
288
  }
286
- /** body: non-empty markdown, ≤500 lines (hard ceiling; the 400-line soft warning is a skillLint). */
289
+ /** body: non-empty markdown, ≤5000 lines (hard ceiling; the 400-line soft warning is a skillLint). */
287
290
  function skillBody(obj, path) {
288
291
  const v = str(obj, "body", `${path}.body`);
289
292
  if (v.split("\n").length > SKILL_BODY_MAX_LINES) {
@@ -333,7 +336,7 @@ export function validateSkill(raw) {
333
336
  export function skillLints(block) {
334
337
  const lints = [];
335
338
  if (block.body.split("\n").length >= SKILL_BODY_WARN_LINES) {
336
- lints.push({ field: "body", message: `body is approaching the ${SKILL_BODY_MAX_LINES}-line limit; split into references` });
339
+ lints.push({ field: "body", message: `body is over ${SKILL_BODY_WARN_LINES} lines; consider splitting into references` });
337
340
  }
338
341
  if (block.name.includes("anthropic") || block.name.includes("claude")) {
339
342
  lints.push({ field: "name", message: 'name contains the reserved word "anthropic" or "claude" — confirm this is legitimate first-party content, not impersonation' });
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@baselane/packs",
3
- "version": "0.1.1",
3
+ "version": "0.1.3",
4
4
  "type": "module",
5
5
  "description": "WorkflowPack schema, validation, and render pipeline, plus the built-in packs shipped by the baselane CLI.",
6
6
  "main": "./dist/index.js",
@@ -22,7 +22,7 @@
22
22
  "access": "public"
23
23
  },
24
24
  "dependencies": {
25
- "@baselane/analyze": "0.1.1"
25
+ "@baselane/analyze": "0.1.3"
26
26
  },
27
27
  "devDependencies": {
28
28
  "@types/node": "^24.0.0",